1 /*
2  * Copyright (C) 2022 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 package com.android.quicksearchbox
17 
18 import android.app.AlarmManager
19 import android.content.Context
20 import android.net.Uri
21 import android.os.Process
22 import java.util.HashSet
23 
24 /**
25  * Provides values for configurable parameters in all of QSB.
26  *
27  * All the methods in this class return fixed default values. Subclasses may make these values
28  * server-side settable.
29  */
30 class Config(context: Context?) {
31   private val mContext: Context?
32   private val mDefaultCorpora: HashSet<String>? = null
33   private val mHiddenCorpora: HashSet<String>? = null
34   private val mDefaultCorporaSuggestUris: HashSet<String>? = null
35   protected val context: Context?
36     get() = mContext
37 
38   /**
39    * Releases any resources used by the configuration object.
40    *
41    * Default implementation does nothing.
42    */
closenull43   fun close() {}
loadResourceStringSetnull44   private fun loadResourceStringSet(res: Int): HashSet<String> {
45     val set: HashSet<String> = HashSet<String>()
46     val items: Array<String> = mContext?.getResources()!!.getStringArray(res)
47     for (item in items) {
48       set.add(item)
49     }
50     return set
51   }
52 
53   /** The number of promoted sources. */
54   val numPromotedSources: Int
55     get() =
56       NUM_PROMOTED_SOURCES // Get the list of default corpora from a resource, which allows vendor
57   // overlays.
58 
59   /** The number of suggestions visible above the onscreen keyboard. */
60   val numSuggestionsAboveKeyboard: Int
61     get() = // Get the list of default corpora from a resource, which allows vendor overlays.
62     mContext?.getResources()!!.getInteger(R.integer.num_suggestions_above_keyboard)
63 
64   /** The maximum number of suggestions to promote. */
65   val maxPromotedSuggestions: Int
66     get() = mContext?.getResources()!!.getInteger(R.integer.max_promoted_suggestions)
67 
68   val maxPromotedResults: Int
69     get() = mContext?.getResources()!!.getInteger(R.integer.max_promoted_results)
70 
71   /** The number of results to ask each source for. */
72   val maxResultsPerSource: Int
73     get() = MAX_RESULTS_PER_SOURCE
74 
75   /** The maximum number of shortcuts to show for the web source in All mode. */
76   val maxShortcutsPerWebSource: Int
77     get() = mContext?.getResources()!!.getInteger(R.integer.max_shortcuts_per_web_source)
78 
79   /** The maximum number of shortcuts to show for each non-web source in All mode. */
80   val maxShortcutsPerNonWebSource: Int
81     get() = mContext?.getResources()!!.getInteger(R.integer.max_shortcuts_per_non_web_source)
82 
83   /** Gets the maximum number of shortcuts that will be shown from the given source. */
84   @Suppress("UNUSED_PARAMETER")
getMaxShortcutsnull85   fun getMaxShortcuts(sourceName: String?): Int {
86     return maxShortcutsPerNonWebSource
87   }
88 
89   /** The timeout for querying each source, in milliseconds. */
90   val sourceTimeoutMillis: Long
91     get() = SOURCE_TIMEOUT_MILLIS
92 
93   /**
94    * The priority of query threads.
95    *
96    * @return A thread priority, as defined in [Process].
97    */
98   val queryThreadPriority: Int
99     get() = QUERY_THREAD_PRIORITY
100 
101   /** The maximum age of log data used for shortcuts. */
102   val maxStatAgeMillis: Long
103     get() = MAX_STAT_AGE_MILLIS
104 
105   /** The minimum number of clicks needed to rank a source. */
106   val minClicksForSourceRanking: Int
107     get() = MIN_CLICKS_FOR_SOURCE_RANKING
108 
109   val numWebCorpusThreads: Int
110     get() = NUM_WEB_CORPUS_THREADS
111 
112   /**
113    * How often query latency should be logged.
114    *
115    * @return An integer in the range 0-1000. 0 means that no latency events should be logged. 1000
116    * means that all latency events should be logged.
117    */
118   val latencyLogFrequency: Int
119     get() = LATENCY_LOG_FREQUENCY
120 
121   /**
122    * The delay in milliseconds before suggestions are updated while typing. If a new character is
123    * typed before this timeout expires, the timeout is reset.
124    */
125   val typingUpdateSuggestionsDelayMillis: Long
126     get() = TYPING_SUGGESTIONS_UPDATE_DELAY_MILLIS
127 
allowVoiceSearchHintsnull128   fun allowVoiceSearchHints(): Boolean {
129     return true
130   }
131 
132   /**
133    * The period of time for which after installing voice search we should consider showing voice
134    * search hints.
135    *
136    * @return The period in milliseconds.
137    */
138   val voiceSearchHintActivePeriod: Long
139     get() = VOICE_SEARCH_HINT_ACTIVE_PERIOD
140 
141   /**
142    * The time interval at which we should consider whether or not to show some voice search hints.
143    *
144    * @return The period in milliseconds.
145    */
146   val voiceSearchHintUpdatePeriod: Long
147     get() = VOICE_SEARCH_HINT_UPDATE_INTERVAL
148 
149   /**
150    * The time interval at which, on average, voice search hints are displayed.
151    *
152    * @return The period in milliseconds.
153    */
154   val voiceSearchHintShowPeriod: Long
155     get() = VOICE_SEARCH_HINT_SHOW_PERIOD_MILLIS
156 
157   /**
158    * The amount of time for which voice search hints are displayed in one go.
159    *
160    * @return The period in milliseconds.
161    */
162   val voiceSearchHintVisibleTime: Long
163     get() = VOICE_SEARCH_HINT_VISIBLE_PERIOD
164 
165   /**
166    * The period that we change voice search hints at while they're being displayed.
167    *
168    * @return The period in milliseconds.
169    */
170   val voiceSearchHintChangePeriod: Long
171     get() = VOICE_SEARCH_HINT_CHANGE_PERIOD
172 
showSuggestionsForZeroQuerynull173   fun showSuggestionsForZeroQuery(): Boolean {
174     // Get the list of default corpora from a resource, which allows vendor overlays.
175     return mContext?.getResources()!!.getBoolean(R.bool.show_zero_query_suggestions)
176   }
177 
showShortcutsForZeroQuerynull178   fun showShortcutsForZeroQuery(): Boolean {
179     // Get the list of default corpora from a resource, which allows vendor overlays.
180     return mContext?.getResources()!!.getBoolean(R.bool.show_zero_query_shortcuts)
181   }
182 
showScrollingSuggestionsnull183   fun showScrollingSuggestions(): Boolean {
184     return mContext?.getResources()!!.getBoolean(R.bool.show_scrolling_suggestions)
185   }
186 
showScrollingResultsnull187   fun showScrollingResults(): Boolean {
188     return mContext?.getResources()!!.getBoolean(R.bool.show_scrolling_results)
189   }
190 
191   @Suppress("UNUSED_PARAMETER")
getHelpUrlnull192   fun getHelpUrl(activity: String?): Uri? {
193     return null
194   }
195 
196   val httpConnectTimeout: Int
197     get() = HTTP_CONNECT_TIMEOUT_MILLIS
198 
199   val httpReadTimeout: Int
200     get() = HTTP_READ_TIMEOUT_MILLIS
201 
202   val userAgent: String
203     get() = USER_AGENT
204 
205   companion object {
206     protected const val SECOND_MILLIS = 1000L
207 
208     @JvmField protected val MINUTE_MILLIS: Long = 60L * SECOND_MILLIS
209     private val VOICE_SEARCH_HINT_CHANGE_PERIOD: Long = 2L * MINUTE_MILLIS
210     private val VOICE_SEARCH_HINT_VISIBLE_PERIOD: Long = 6L * MINUTE_MILLIS
211     protected const val DAY_MILLIS = 86400000L
212     private const val TAG = "QSB.Config"
213     private const val DBG = false
214     private const val NUM_PROMOTED_SOURCES = 3
215     private const val MAX_RESULTS_PER_SOURCE = 50
216     private const val SOURCE_TIMEOUT_MILLIS: Long = 10000
217     private val QUERY_THREAD_PRIORITY: Int =
218       Process.THREAD_PRIORITY_BACKGROUND + Process.THREAD_PRIORITY_MORE_FAVORABLE
219     private val MAX_STAT_AGE_MILLIS: Long = 30 * DAY_MILLIS
220     private const val MIN_CLICKS_FOR_SOURCE_RANKING = 3
221     private const val NUM_WEB_CORPUS_THREADS = 2
222     private const val LATENCY_LOG_FREQUENCY = 1000
223     private const val TYPING_SUGGESTIONS_UPDATE_DELAY_MILLIS: Long = 100
224     private const val PUBLISH_RESULT_DELAY_MILLIS: Long = 200
225     private val VOICE_SEARCH_HINT_ACTIVE_PERIOD: Long = 7L * DAY_MILLIS
226     private val VOICE_SEARCH_HINT_UPDATE_INTERVAL: Long = AlarmManager.INTERVAL_FIFTEEN_MINUTES
227     private val VOICE_SEARCH_HINT_SHOW_PERIOD_MILLIS: Long = AlarmManager.INTERVAL_HOUR * 2
228     private const val HTTP_CONNECT_TIMEOUT_MILLIS = 4000
229     private const val HTTP_READ_TIMEOUT_MILLIS = 4000
230     private const val USER_AGENT = "Android/1.0"
231   }
232 
233   /** Creates a new config that uses hard-coded default values. */
234   init {
235     mContext = context
236   }
237 }
238