SearchSettingsImpl.java revision 8074f659cbe5406f0a31c8d1cd764660964f0d53
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 com.android.common.SharedPreferencesCompat; 20 21import android.app.SearchManager; 22import android.content.Context; 23import android.content.Intent; 24import android.content.SharedPreferences; 25import android.content.SharedPreferences.Editor; 26import android.util.Log; 27import android.view.Menu; 28import android.view.MenuInflater; 29import android.view.MenuItem; 30 31/** 32 * Manages user settings. 33 */ 34public 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 private static final String SEARCH_BASE_URL = "search_base_url"; 68 69 /** 70 * This is the time at which the base URL was stored, and is set using 71 * @link{System.currentTimeMillis()}. 72 */ 73 private static final String SEARCH_BASE_URL_APPLY_TIME = "search_base_url_apply_time"; 74 75 /** 76 * Prefix of per-corpus enable preference 77 */ 78 private static final String CORPUS_ENABLED_PREF_PREFIX = "enable_corpus_"; 79 80 private final Context mContext; 81 82 private final Config mConfig; 83 84 public SearchSettingsImpl(Context context, Config config) { 85 mContext = context; 86 mConfig = config; 87 } 88 89 protected Context getContext() { 90 return mContext; 91 } 92 93 protected Config getConfig() { 94 return mConfig; 95 } 96 97 public void upgradeSettingsIfNeeded() { 98 } 99 100 public Intent getSearchableItemsIntent() { 101 Intent intent = new Intent(ACTION_SEARCHABLE_ITEMS); 102 intent.setPackage(getContext().getPackageName()); 103 return intent; 104 } 105 106 /** 107 * Gets the preference key of the preference for whether the given corpus 108 * is enabled. The preference is stored in the {@link #PREFERENCES_NAME} 109 * preferences file. 110 */ 111 public static String getCorpusEnabledPreference(Corpus corpus) { 112 return CORPUS_ENABLED_PREF_PREFIX + corpus.getName(); 113 } 114 115 public boolean isCorpusEnabled(Corpus corpus) { 116 boolean defaultEnabled = corpus.isCorpusDefaultEnabled(); 117 String sourceEnabledPref = getCorpusEnabledPreference(corpus); 118 return getSearchPreferences().getBoolean(sourceEnabledPref, defaultEnabled); 119 } 120 121 protected SharedPreferences getSearchPreferences() { 122 return getContext().getSharedPreferences(PREFERENCES_NAME, Context.MODE_PRIVATE); 123 } 124 125 protected void storeBoolean(String name, boolean value) { 126 SharedPreferencesCompat.apply(getSearchPreferences().edit().putBoolean(name, value)); 127 } 128 129 protected void storeInt(String name, int value) { 130 SharedPreferencesCompat.apply(getSearchPreferences().edit().putInt(name, value)); 131 } 132 133 protected void storeLong(String name, long value) { 134 SharedPreferencesCompat.apply(getSearchPreferences().edit().putLong(name, value)); 135 } 136 137 protected void storeString(String name, String value) { 138 SharedPreferencesCompat.apply(getSearchPreferences().edit().putString(name, value)); 139 } 140 141 protected void removePref(String name) { 142 SharedPreferencesCompat.apply(getSearchPreferences().edit().remove(name)); 143 } 144 145 /** 146 * Informs our listeners about the updated settings data. 147 */ 148 public void broadcastSettingsChanged() { 149 // We use a message broadcast since the listeners could be in multiple processes. 150 Intent intent = new Intent(SearchManager.INTENT_ACTION_SEARCH_SETTINGS_CHANGED); 151 Log.i(TAG, "Broadcasting: " + intent); 152 getContext().sendBroadcast(intent); 153 } 154 155 public void addMenuItems(Menu menu, boolean showDisabled) { 156 MenuInflater inflater = new MenuInflater(getContext()); 157 inflater.inflate(R.menu.settings, menu); 158 MenuItem item = menu.findItem(R.id.menu_settings); 159 item.setIntent(getSearchSettingsIntent()); 160 } 161 162 public Intent getSearchSettingsIntent() { 163 Intent settings = new Intent(SearchManager.INTENT_ACTION_SEARCH_SETTINGS); 164 settings.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET); 165 settings.setPackage(getContext().getPackageName()); 166 return settings; 167 } 168 169 public int getNextVoiceSearchHintIndex(int size) { 170 int i = getAndIncrementIntPreference(getSearchPreferences(), 171 NEXT_VOICE_SEARCH_HINT_INDEX_PREF); 172 return i % size; 173 } 174 175 // TODO: Could this be made atomic to avoid races? 176 private int getAndIncrementIntPreference(SharedPreferences prefs, String name) { 177 int i = prefs.getInt(name, 0); 178 storeInt(name, i + 1); 179 return i; 180 } 181 182 public void resetVoiceSearchHintFirstSeenTime() { 183 storeLong(FIRST_VOICE_HINT_DISPLAY_TIME, System.currentTimeMillis()); 184 } 185 186 public boolean haveVoiceSearchHintsExpired(int currentVoiceSearchVersion) { 187 SharedPreferences prefs = getSearchPreferences(); 188 189 if (currentVoiceSearchVersion != 0) { 190 long currentTime = System.currentTimeMillis(); 191 int lastVoiceSearchVersion = prefs.getInt(LAST_SEEN_VOICE_SEARCH_VERSION, 0); 192 long firstHintTime = prefs.getLong(FIRST_VOICE_HINT_DISPLAY_TIME, 0); 193 if (firstHintTime == 0 || currentVoiceSearchVersion != lastVoiceSearchVersion) { 194 SharedPreferencesCompat.apply(prefs.edit() 195 .putInt(LAST_SEEN_VOICE_SEARCH_VERSION, currentVoiceSearchVersion) 196 .putLong(FIRST_VOICE_HINT_DISPLAY_TIME, currentTime)); 197 firstHintTime = currentTime; 198 } 199 if (currentTime - firstHintTime > getConfig().getVoiceSearchHintActivePeriod()) { 200 if (DBG) Log.d(TAG, "Voice seach hint period expired; not showing hints."); 201 return true; 202 } else { 203 return false; 204 } 205 } else { 206 if (DBG) Log.d(TAG, "Could not determine voice search version; not showing hints."); 207 return true; 208 } 209 } 210 211 public boolean allowWebSearchShortcuts() { 212 return true; 213 } 214 215 /** 216 * @return true if user searches should always be based at google.com, false 217 * otherwise. 218 */ 219 @Override 220 public boolean shouldUseGoogleCom() { 221 // Note that this preserves the old behaviour of using google.com 222 // for searches, with the gl= parameter set. 223 return getSearchPreferences().getBoolean(USE_GOOGLE_COM_PREF, true); 224 } 225 226 @Override 227 public void setUseGoogleCom(boolean useGoogleCom) { 228 storeBoolean(USE_GOOGLE_COM_PREF, useGoogleCom); 229 } 230 231 @Override 232 public long getSearchBaseUrlApplyTime() { 233 return getSearchPreferences().getLong(SEARCH_BASE_URL_APPLY_TIME, -1); 234 } 235 236 @Override 237 public String getSearchBaseUrl() { 238 // Its better that an exception is thrown at this point, because 239 // this should always be called after checking that 240 // getSearchBaseUrlApplyTime() >= 0. 241 return getSearchPreferences().getString(SEARCH_BASE_URL, null); 242 } 243 244 @Override 245 public void setSearchBaseUrl(String searchBaseUrl) { 246 Editor sharedPrefEditor = getSearchPreferences().edit(); 247 sharedPrefEditor.putString(SEARCH_BASE_URL, searchBaseUrl); 248 sharedPrefEditor.putLong(SEARCH_BASE_URL_APPLY_TIME, System.currentTimeMillis()); 249 250 SharedPreferencesCompat.apply(sharedPrefEditor); 251 } 252} 253