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.AlarmManager; 20 import android.content.Context; 21 import android.net.Uri; 22 import android.os.Process; 23 import android.util.Log; 24 25 import java.util.HashSet; 26 27 /** 28 * Provides values for configurable parameters in all of QSB. 29 * 30 * All the methods in this class return fixed default values. Subclasses may 31 * make these values server-side settable. 32 * 33 */ 34 public class Config { 35 36 private static final String TAG = "QSB.Config"; 37 private static final boolean DBG = false; 38 39 protected static final long SECOND_MILLIS = 1000L; 40 protected static final long MINUTE_MILLIS = 60L * SECOND_MILLIS; 41 protected static final long DAY_MILLIS = 86400000L; 42 43 private static final int NUM_PROMOTED_SOURCES = 3; 44 private static final int MAX_RESULTS_PER_SOURCE = 50; 45 private static final long SOURCE_TIMEOUT_MILLIS = 10000; 46 47 private static final int QUERY_THREAD_PRIORITY = 48 Process.THREAD_PRIORITY_BACKGROUND + Process.THREAD_PRIORITY_MORE_FAVORABLE; 49 50 private static final long MAX_STAT_AGE_MILLIS = 30 * DAY_MILLIS; 51 private static final int MIN_CLICKS_FOR_SOURCE_RANKING = 3; 52 53 private static final int NUM_WEB_CORPUS_THREADS = 2; 54 55 private static final int LATENCY_LOG_FREQUENCY = 1000; 56 57 private static final long TYPING_SUGGESTIONS_UPDATE_DELAY_MILLIS = 100; 58 private static final long PUBLISH_RESULT_DELAY_MILLIS = 200; 59 60 private static final long VOICE_SEARCH_HINT_ACTIVE_PERIOD = 7L * DAY_MILLIS; 61 62 private static final long VOICE_SEARCH_HINT_UPDATE_INTERVAL 63 = AlarmManager.INTERVAL_FIFTEEN_MINUTES; 64 65 private static final long VOICE_SEARCH_HINT_SHOW_PERIOD_MILLIS 66 = AlarmManager.INTERVAL_HOUR * 2; 67 68 private static final long VOICE_SEARCH_HINT_CHANGE_PERIOD = 2L * MINUTE_MILLIS; 69 70 private static final long VOICE_SEARCH_HINT_VISIBLE_PERIOD = 6L * MINUTE_MILLIS; 71 72 private static final int HTTP_CONNECT_TIMEOUT_MILLIS = 4000; 73 private static final int HTTP_READ_TIMEOUT_MILLIS = 4000; 74 75 private static final String USER_AGENT = "Android/1.0"; 76 77 private final Context mContext; 78 private HashSet<String> mDefaultCorpora; 79 private HashSet<String> mHiddenCorpora; 80 private HashSet<String> mDefaultCorporaSuggestUris; 81 82 /** 83 * Creates a new config that uses hard-coded default values. 84 */ 85 public Config(Context context) { 86 mContext = context; 87 } 88 89 protected Context getContext() { 90 return mContext; 91 } 92 93 /** 94 * Releases any resources used by the configuration object. 95 * 96 * Default implementation does nothing. 97 */ 98 public void close() { 99 } 100 101 private HashSet<String> loadResourceStringSet(int res) { 102 HashSet<String> defaultCorpora = new HashSet<String>(); 103 String[] corpora = mContext.getResources().getStringArray(res); 104 for (String corpus : corpora) { 105 if (DBG) Log.d(TAG, "Default corpus: " + corpus); 106 defaultCorpora.add(corpus); 107 } 108 return defaultCorpora; 109 } 110 111 /** 112 * Checks if we trust the given source not to be spammy. 113 */ 114 public synchronized boolean isCorpusEnabledByDefault(Corpus corpus) { 115 if (DBG) Log.d(TAG, "isCorpusEnabledByDefault(" + corpus.getName() + ")"); 116 if (mDefaultCorpora == null) { 117 mDefaultCorpora = loadResourceStringSet(R.array.default_corpora); 118 } 119 if (mDefaultCorpora.contains(corpus.getName())) { 120 if (DBG) Log.d(TAG, "Corpus " + corpus.getName() + " IS default"); 121 return true; 122 } 123 124 if (mDefaultCorporaSuggestUris == null) { 125 mDefaultCorporaSuggestUris = loadResourceStringSet( 126 R.array.default_corpora_suggest_uris); 127 } 128 129 for (Source s : corpus.getSources()) { 130 String uri = s.getSuggestUri(); 131 if (DBG) Log.d(TAG, "Suggest URI for " + corpus.getName() + ": " + uri); 132 if (mDefaultCorporaSuggestUris.contains(uri)) { 133 if (DBG) Log.d(TAG, "Corpus " + corpus.getName() + " IS default"); 134 return true; 135 } 136 } 137 if (DBG) Log.d(TAG, "Corpus " + corpus.getName() + " is NOT default"); 138 return false; 139 } 140 141 /** 142 * Checks if the given corpus should be hidden from the corpus selection dialog. 143 */ 144 public synchronized boolean isCorpusHidden(String corpusName) { 145 if (mHiddenCorpora == null) { 146 mHiddenCorpora = loadResourceStringSet(R.array.hidden_corpora); 147 } 148 return mHiddenCorpora.contains(corpusName); 149 } 150 151 /** 152 * The number of promoted sources. 153 */ 154 public int getNumPromotedSources() { 155 return NUM_PROMOTED_SOURCES; 156 } 157 158 /** 159 * The number of suggestions visible above the onscreen keyboard. 160 */ 161 public int getNumSuggestionsAboveKeyboard() { 162 // Get the list of default corpora from a resource, which allows vendor overlays. 163 return mContext.getResources().getInteger(R.integer.num_suggestions_above_keyboard); 164 } 165 166 /** 167 * The maximum number of suggestions to promote. 168 */ 169 public int getMaxPromotedSuggestions() { 170 return mContext.getResources().getInteger(R.integer.max_promoted_suggestions); 171 } 172 173 public int getMaxPromotedResults() { 174 return mContext.getResources().getInteger(R.integer.max_promoted_results); 175 } 176 177 /** 178 * The number of results to ask each source for. 179 */ 180 public int getMaxResultsPerSource() { 181 return MAX_RESULTS_PER_SOURCE; 182 } 183 184 /** 185 * The maximum number of shortcuts to show for the web source in All mode. 186 */ 187 public int getMaxShortcutsPerWebSource() { 188 return mContext.getResources().getInteger(R.integer.max_shortcuts_per_web_source); 189 } 190 191 /** 192 * The maximum number of shortcuts to show for each non-web source in All mode. 193 */ 194 public int getMaxShortcutsPerNonWebSource() { 195 return mContext.getResources().getInteger(R.integer.max_shortcuts_per_non_web_source); 196 } 197 198 /** 199 * Gets the maximum number of shortcuts that will be shown from the given source. 200 */ 201 public int getMaxShortcuts(String sourceName) { 202 return getMaxShortcutsPerNonWebSource(); 203 } 204 205 /** 206 * The timeout for querying each source, in milliseconds. 207 */ 208 public long getSourceTimeoutMillis() { 209 return SOURCE_TIMEOUT_MILLIS; 210 } 211 212 /** 213 * The priority of query threads. 214 * 215 * @return A thread priority, as defined in {@link Process}. 216 */ 217 public int getQueryThreadPriority() { 218 return QUERY_THREAD_PRIORITY; 219 } 220 221 /** 222 * The maximum age of log data used for shortcuts. 223 */ 224 public long getMaxStatAgeMillis(){ 225 return MAX_STAT_AGE_MILLIS; 226 } 227 228 /** 229 * The minimum number of clicks needed to rank a source. 230 */ 231 public int getMinClicksForSourceRanking(){ 232 return MIN_CLICKS_FOR_SOURCE_RANKING; 233 } 234 235 public int getNumWebCorpusThreads() { 236 return NUM_WEB_CORPUS_THREADS; 237 } 238 239 /** 240 * How often query latency should be logged. 241 * 242 * @return An integer in the range 0-1000. 0 means that no latency events 243 * should be logged. 1000 means that all latency events should be logged. 244 */ 245 public int getLatencyLogFrequency() { 246 return LATENCY_LOG_FREQUENCY; 247 } 248 249 /** 250 * The delay in milliseconds before suggestions are updated while typing. 251 * If a new character is typed before this timeout expires, the timeout is reset. 252 */ 253 public long getTypingUpdateSuggestionsDelayMillis() { 254 return TYPING_SUGGESTIONS_UPDATE_DELAY_MILLIS; 255 } 256 257 /** 258 * The delay in milliseconds before corpus results are published. 259 * If a new result arrives before this timeout expires, the timeout is reset. 260 */ 261 public long getPublishResultDelayMillis() { 262 return PUBLISH_RESULT_DELAY_MILLIS; 263 } 264 265 public boolean allowVoiceSearchHints() { 266 return true; 267 } 268 269 /** 270 * The period of time for which after installing voice search we should consider showing voice 271 * search hints. 272 * 273 * @return The period in milliseconds. 274 */ 275 public long getVoiceSearchHintActivePeriod() { 276 return VOICE_SEARCH_HINT_ACTIVE_PERIOD; 277 } 278 279 /** 280 * The time interval at which we should consider whether or not to show some voice search hints. 281 * 282 * @return The period in milliseconds. 283 */ 284 public long getVoiceSearchHintUpdatePeriod() { 285 return VOICE_SEARCH_HINT_UPDATE_INTERVAL; 286 } 287 288 /** 289 * The time interval at which, on average, voice search hints are displayed. 290 * 291 * @return The period in milliseconds. 292 */ 293 public long getVoiceSearchHintShowPeriod() { 294 return VOICE_SEARCH_HINT_SHOW_PERIOD_MILLIS; 295 } 296 297 /** 298 * The amount of time for which voice search hints are displayed in one go. 299 * 300 * @return The period in milliseconds. 301 */ 302 public long getVoiceSearchHintVisibleTime() { 303 return VOICE_SEARCH_HINT_VISIBLE_PERIOD; 304 } 305 306 /** 307 * The period that we change voice search hints at while they're being displayed. 308 * 309 * @return The period in milliseconds. 310 */ 311 public long getVoiceSearchHintChangePeriod() { 312 return VOICE_SEARCH_HINT_CHANGE_PERIOD; 313 } 314 315 public boolean showSuggestionsForZeroQuery() { 316 // Get the list of default corpora from a resource, which allows vendor overlays. 317 return mContext.getResources().getBoolean(R.bool.show_zero_query_suggestions); 318 } 319 320 public boolean showShortcutsForZeroQuery() { 321 // Get the list of default corpora from a resource, which allows vendor overlays. 322 return mContext.getResources().getBoolean(R.bool.show_zero_query_shortcuts); 323 } 324 325 public boolean showScrollingSuggestions() { 326 return mContext.getResources().getBoolean(R.bool.show_scrolling_suggestions); 327 } 328 329 public boolean showScrollingResults() { 330 return mContext.getResources().getBoolean(R.bool.show_scrolling_results); 331 } 332 333 public Uri getHelpUrl(String activity) { 334 return null; 335 } 336 337 public int getHttpConnectTimeout() { 338 return HTTP_CONNECT_TIMEOUT_MILLIS; 339 } 340 341 public int getHttpReadTimeout() { 342 return HTTP_READ_TIMEOUT_MILLIS; 343 } 344 345 public String getUserAgent() { 346 return USER_AGENT; 347 } 348 } 349