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