2 * Copyright 2016-2023 Soren Stoutner <soren@stoutner.com>.
4 * This file is part of Privacy Browser Android <https://www.stoutner.com/privacy-browser-android>.
6 * Privacy Browser Android is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * Privacy Browser Android is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with Privacy Browser Android. If not, see <http://www.gnu.org/licenses/>.
20 package com.stoutner.privacybrowser.fragments
22 import android.annotation.SuppressLint
23 import android.content.Intent
24 import android.content.SharedPreferences
25 import android.content.SharedPreferences.OnSharedPreferenceChangeListener
26 import android.content.res.Configuration
27 import android.os.Build
28 import android.os.Bundle
29 import android.os.Handler
30 import android.os.Looper
31 import android.webkit.WebView
32 import android.widget.ArrayAdapter
34 import androidx.appcompat.app.AppCompatDelegate
35 import androidx.preference.Preference
36 import androidx.preference.PreferenceCategory
37 import androidx.preference.PreferenceFragmentCompat
39 import com.stoutner.privacybrowser.R
40 import com.stoutner.privacybrowser.activities.SETTINGS_CUSTOM_USER_AGENT
41 import com.stoutner.privacybrowser.activities.SETTINGS_WEBVIEW_DEFAULT_USER_AGENT
42 import com.stoutner.privacybrowser.activities.UNRECOGNIZED_USER_AGENT
43 import com.stoutner.privacybrowser.helpers.ProxyHelper
44 import kotlin.system.exitProcess
46 // Define the class constants.
47 private const val SCROLL_Y = "scroll_y"
49 class SettingsFragment : PreferenceFragmentCompat() {
51 // Declare the private static class variables. For some reason (I'm looking at you Android's Activity Lifecycle) this only works if these are static.
52 private var fragmentRestarted: Boolean = false
53 private var scrollY: Int = 0
56 // Declare the class variables.
57 private lateinit var allowScreenshotsPreference: Preference
58 private lateinit var ampRedirectsPreference: Preference
59 private lateinit var appThemeEntriesStringArray: Array<String>
60 private lateinit var appThemeEntryValuesStringArray: Array<String>
61 private lateinit var appThemePreference: Preference
62 private lateinit var blockAllThirdPartyRequestsPreference: Preference
63 private lateinit var bottomAppBarPreference: Preference
64 private lateinit var clearCachePreference: Preference
65 private lateinit var clearCookiesPreference: Preference
66 private lateinit var clearDomStoragePreference: Preference
67 private lateinit var clearEverythingPreference: Preference
68 private lateinit var clearFormDataPreference: Preference // The clear form data preference can be removed once the minimum API >= 26.
69 private lateinit var clearLogcatPreference: Preference
70 private lateinit var cookiesPreference: Preference
71 private lateinit var customUserAgentPreference: Preference
72 private lateinit var defaultUserAgent: String
73 private lateinit var displayAdditionalAppBarIconsPreference: Preference
74 private lateinit var displayWebpageImagesPreference: Preference
75 private lateinit var domStoragePreference: Preference
76 private lateinit var downloadWithExternalAppPreference: Preference
77 private lateinit var easyListPreference: Preference
78 private lateinit var easyPrivacyPreference: Preference
79 private lateinit var fanboyAnnoyanceListPreference: Preference
80 private lateinit var fanboySocialBlockingListPreference: Preference
81 private lateinit var fontSizePreference: Preference
82 private lateinit var formDataPreference: Preference // The form data preference can be removed once the minimum API >= 26.
83 private lateinit var fullScreenBrowsingModePreference: Preference
84 private lateinit var hideAppBarPreference: Preference
85 private lateinit var homepagePreference: Preference
86 private lateinit var incognitoModePreference: Preference
87 private lateinit var javaScriptPreference: Preference
88 private lateinit var openIntentsInNewTabPreference: Preference
89 private lateinit var proxyCustomUrlPreference: Preference
90 private lateinit var proxyPreference: Preference
91 private lateinit var scrollAppBarPreference: Preference
92 private lateinit var searchCustomURLPreference: Preference
93 private lateinit var searchPreference: Preference
94 private lateinit var sharedPreferenceChangeListener: OnSharedPreferenceChangeListener
95 private lateinit var swipeToRefreshPreference: Preference
96 private lateinit var trackingQueriesPreference: Preference
97 private lateinit var translatedUserAgentNamesArray: Array<String>
98 private lateinit var ultraListPreference: Preference
99 private lateinit var ultraPrivacyPreference: Preference
100 private lateinit var userAgentDataArray: Array<String>
101 private lateinit var userAgentPreference: Preference
102 private lateinit var userAgentNamesArray: ArrayAdapter<CharSequence>
103 private lateinit var webViewThemeEntriesStringArray: Array<String>
104 private lateinit var webViewThemeEntryValuesStringArray: Array<String>
105 private lateinit var webViewThemePreference: Preference
106 private lateinit var wideViewportPreference: Preference
108 override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
109 // Check if the fragment has been restarted.
110 if (savedInstanceState != null) {
111 // Set the fragment restored flag.
112 fragmentRestarted = true
114 // Save the scroll Y.
115 scrollY = savedInstanceState.getInt(SCROLL_Y)
118 // Load the preferences from the XML file.
119 setPreferencesFromResource(R.xml.preferences, rootKey)
121 // Get a handle for the shared preferences.
122 val sharedPreferences = preferenceScreen.sharedPreferences!!
124 // Get handles for the preferences.
125 javaScriptPreference = findPreference(getString(R.string.javascript_key))!!
126 cookiesPreference = findPreference(getString(R.string.cookies_key))!!
127 domStoragePreference = findPreference(getString(R.string.dom_storage_key))!!
128 formDataPreference = findPreference(getString(R.string.save_form_data_key))!! // The form data preference can be removed once the minimum API >= 26.
129 userAgentPreference = findPreference(getString(R.string.user_agent_key))!!
130 customUserAgentPreference = findPreference(getString(R.string.custom_user_agent_key))!!
131 incognitoModePreference = findPreference(getString(R.string.incognito_mode_key))!!
132 allowScreenshotsPreference = findPreference(getString(R.string.allow_screenshots_key))!!
133 easyListPreference = findPreference(getString(R.string.easylist_key))!!
134 easyPrivacyPreference = findPreference(getString(R.string.easyprivacy_key))!!
135 fanboyAnnoyanceListPreference = findPreference(getString(R.string.fanboys_annoyance_list_key))!!
136 fanboySocialBlockingListPreference = findPreference(getString(R.string.fanboys_social_blocking_list_key))!!
137 ultraListPreference = findPreference(getString(R.string.ultralist_key))!!
138 ultraPrivacyPreference = findPreference(getString(R.string.ultraprivacy_key))!!
139 blockAllThirdPartyRequestsPreference = findPreference(getString(R.string.block_all_third_party_requests_key))!!
140 trackingQueriesPreference = findPreference(getString(R.string.tracking_queries_key))!!
141 ampRedirectsPreference = findPreference(getString(R.string.amp_redirects_key))!!
142 searchPreference = findPreference(getString(R.string.search_key))!!
143 searchCustomURLPreference = findPreference(getString(R.string.search_custom_url_key))!!
144 proxyPreference = findPreference(getString(R.string.proxy_key))!!
145 proxyCustomUrlPreference = findPreference(getString(R.string.proxy_custom_url_key))!!
146 fullScreenBrowsingModePreference = findPreference(getString(R.string.full_screen_browsing_mode_key))!!
147 hideAppBarPreference = findPreference(getString(R.string.hide_app_bar_key))!!
148 clearEverythingPreference = findPreference(getString(R.string.clear_everything_key))!!
149 clearCookiesPreference = findPreference(getString(R.string.clear_cookies_key))!!
150 clearDomStoragePreference = findPreference(getString(R.string.clear_dom_storage_key))!!
151 clearFormDataPreference = findPreference(getString(R.string.clear_form_data_key))!! // The clear form data preference can be removed once the minimum API >= 26.
152 clearLogcatPreference = findPreference(getString(R.string.clear_logcat_key))!!
153 clearCachePreference = findPreference(getString(R.string.clear_cache_key))!!
154 homepagePreference = findPreference(getString(R.string.homepage_key))!!
155 fontSizePreference = findPreference(getString(R.string.font_size_key))!!
156 openIntentsInNewTabPreference = findPreference(getString(R.string.open_intents_in_new_tab_key))!!
157 swipeToRefreshPreference = findPreference(getString(R.string.swipe_to_refresh_key))!!
158 downloadWithExternalAppPreference = findPreference(getString(R.string.download_with_external_app_key))!!
159 scrollAppBarPreference = findPreference(getString(R.string.scroll_app_bar_key))!!
160 bottomAppBarPreference = findPreference(getString(R.string.bottom_app_bar_key))!!
161 displayAdditionalAppBarIconsPreference = findPreference(getString(R.string.display_additional_app_bar_icons_key))!!
162 appThemePreference = findPreference(getString(R.string.app_theme_key))!!
163 webViewThemePreference = findPreference(getString(R.string.webview_theme_key))!!
164 wideViewportPreference = findPreference(getString(R.string.wide_viewport_key))!!
165 displayWebpageImagesPreference = findPreference(getString(R.string.display_webpage_images_key))!!
167 // Set the preference dependencies.
168 domStoragePreference.dependency = getString(R.string.javascript_key)
169 hideAppBarPreference.dependency = getString(R.string.full_screen_browsing_mode_key)
171 // Get strings from the preferences.
172 val userAgentName = sharedPreferences.getString(getString(R.string.user_agent_key), getString(R.string.user_agent_default_value))
173 val searchString = sharedPreferences.getString(getString(R.string.search_key), getString(R.string.search_default_value))
174 val proxyString = sharedPreferences.getString(getString(R.string.proxy_key), getString(R.string.proxy_default_value))
176 // Get booleans that are used in multiple places from the preferences.
177 val javaScriptEnabled = sharedPreferences.getBoolean(getString(R.string.javascript_key), false)
178 val fanboyAnnoyanceListEnabled = sharedPreferences.getBoolean(getString(R.string.fanboys_annoyance_list_key), true)
179 val fanboySocialBlockingEnabled = sharedPreferences.getBoolean(getString(R.string.fanboys_social_blocking_list_key), true)
180 val fullScreenBrowsingMode = sharedPreferences.getBoolean(getString(R.string.full_screen_browsing_mode_key), false)
181 val clearEverything = sharedPreferences.getBoolean(getString(R.string.clear_everything_key), true)
183 // Remove the form data preferences if the API is >= 26 as they no longer do anything.
184 if (Build.VERSION.SDK_INT >= 26) {
185 // Get handles for the categories.
186 val privacyCategory = findPreference<PreferenceCategory>(getString(R.string.privacy_category_key))!!
187 val clearAndExitCategory = findPreference<PreferenceCategory>(getString(R.string.clear_and_exit_category_key))!!
189 // Remove the form data preferences.
190 privacyCategory.removePreference(formDataPreference)
191 clearAndExitCategory.removePreference(clearFormDataPreference)
194 // Only enable Fanboy's social blocking list preference if Fanboy's annoyance list is disabled.
195 fanboySocialBlockingListPreference.isEnabled = !fanboyAnnoyanceListEnabled
198 // Inflate a WebView to get the default user agent.
199 val inflater = requireActivity().layoutInflater
201 // `@SuppressLint("InflateParams")` removes the warning about using `null` as the `ViewGroup`, which in this case makes sense because the `bare_webview` will not be displayed.
202 @SuppressLint("InflateParams") val bareWebViewLayout = inflater.inflate(R.layout.bare_webview, null, false)
204 // Get a handle for the bare WebView.
205 val bareWebView = bareWebViewLayout.findViewById<WebView>(R.id.bare_webview)
207 // Get the default user agent.
208 defaultUserAgent = bareWebView.settings.userAgentString
210 // Get the user agent arrays.
211 userAgentNamesArray = ArrayAdapter.createFromResource(requireContext(), R.array.user_agent_names, R.layout.spinner_item)
212 translatedUserAgentNamesArray = resources.getStringArray(R.array.translated_user_agent_names)
213 userAgentDataArray = resources.getStringArray(R.array.user_agent_data)
215 // Populate the user agent summary.
216 when (val userAgentArrayPosition = userAgentNamesArray.getPosition(userAgentName)) {
217 // The user agent name is not on the canonical list.
218 // This is probably because it was set in an older version of Privacy Browser before the switch to persistent user agent names. Use the current user agent entry name as the summary.
219 UNRECOGNIZED_USER_AGENT -> userAgentPreference.summary = userAgentName
221 // Get the user agent text from the webview (which changes based on the version of Android and WebView installed).
222 SETTINGS_WEBVIEW_DEFAULT_USER_AGENT -> userAgentPreference.summary = "${translatedUserAgentNamesArray[userAgentArrayPosition]}:\n$defaultUserAgent"
224 // Display the custom user agent.
225 SETTINGS_CUSTOM_USER_AGENT -> userAgentPreference.setSummary(R.string.custom_user_agent)
227 // Get the user agent summary from the user agent data array.
228 else -> userAgentPreference.summary = "${translatedUserAgentNamesArray[userAgentArrayPosition]}:\n${userAgentDataArray[userAgentArrayPosition]}"
231 // Set the summary text for the custom user agent preference.
232 customUserAgentPreference.summary = sharedPreferences.getString(getString(R.string.custom_user_agent_key), getString(R.string.custom_user_agent_default_value))
234 // Only enable the custom user agent preference if the user agent is set to custom.
235 customUserAgentPreference.isEnabled = (userAgentPreference.summary == getString(R.string.custom_user_agent))
237 // Set the search URL as the summary text for the search preference when the preference screen is loaded.
238 if (searchString == getString(R.string.custom_url_item)) {
239 // Use R.string.custom_url, which will be translated, instead of the array value, which will not.
240 searchPreference.setSummary(R.string.custom_url)
242 // Set the array value as the summary text.
243 searchPreference.summary = searchString
246 // Set the summary text for the search custom URL (the default is `""`).
247 searchCustomURLPreference.summary = sharedPreferences.getString(getString(R.string.search_custom_url_key), getString(R.string.search_custom_url_default_value))
249 // Only enable the search custom URL preference if the search is set to a custom URL.
250 searchCustomURLPreference.isEnabled = (searchString == getString(R.string.custom_url_item))
252 // Set the summary text for the proxy preference.
253 proxyPreference.summary = when (proxyString) {
254 ProxyHelper.NONE -> getString(R.string.no_proxy_enabled)
255 ProxyHelper.TOR -> getString(R.string.tor_enabled)
256 ProxyHelper.I2P -> getString(R.string.i2p_enabled)
257 ProxyHelper.CUSTOM -> getString(R.string.custom_proxy)
258 else -> getString(R.string.no_proxy_enabled)
261 // Set the summary text for the custom proxy URL.
262 proxyCustomUrlPreference.summary = sharedPreferences.getString(getString(R.string.proxy_custom_url_key), getString(R.string.proxy_custom_url_default_value))
264 // Only enable the custom proxy URL if a custom proxy is selected.
265 proxyCustomUrlPreference.isEnabled = proxyString == ProxyHelper.CUSTOM
267 // Set the status of the clear and exit preferences.
268 clearCookiesPreference.isEnabled = !clearEverything
269 clearDomStoragePreference.isEnabled = !clearEverything
270 clearFormDataPreference.isEnabled = !clearEverything // Clear form data can be removed once the minimum API is >= 26.
271 clearLogcatPreference.isEnabled = !clearEverything
272 clearCachePreference.isEnabled = !clearEverything
274 // Set the homepage URL as the summary text for the homepage preference.
275 homepagePreference.summary = sharedPreferences.getString(getString(R.string.homepage_key), getString(R.string.homepage_default_value))
277 // Set the font size as the summary text for the preference.
278 fontSizePreference.summary = sharedPreferences.getString(getString(R.string.font_size_key), getString(R.string.font_size_default_value)) + "%"
280 // Get the app theme string arrays.
281 appThemeEntriesStringArray = resources.getStringArray(R.array.app_theme_entries)
282 appThemeEntryValuesStringArray = resources.getStringArray(R.array.app_theme_entry_values)
284 // Get the app theme entry number that matches the current app theme.
285 val appThemeEntryNumber: Int = when (sharedPreferences.getString(getString(R.string.app_theme_key), getString(R.string.app_theme_default_value))) {
286 appThemeEntryValuesStringArray[1] -> 1 // The light theme is selected.
287 appThemeEntryValuesStringArray[2] -> 2 // The dark theme is selected.
288 else -> 0 // The system default theme is selected.
291 // Set the current theme as the summary text for the preference.
292 appThemePreference.summary = appThemeEntriesStringArray[appThemeEntryNumber]
294 // Enable the WebView theme preference if the app theme is not set to light. Google does not allow light themes to display dark WebViews.
295 webViewThemePreference.isEnabled = (appThemeEntryNumber != 1)
297 // Get the WebView theme string arrays.
298 webViewThemeEntriesStringArray = resources.getStringArray(R.array.webview_theme_entries)
299 webViewThemeEntryValuesStringArray = resources.getStringArray(R.array.webview_theme_entry_values)
301 // Get the WebView theme entry number that matches the current WebView theme.
302 val webViewThemeEntryNumber: Int = when (sharedPreferences.getString(getString(R.string.webview_theme_key), getString(R.string.webview_theme_default_value))) {
303 webViewThemeEntryValuesStringArray[1] -> 1 // The light theme is selected.
304 webViewThemeEntryValuesStringArray[2] -> 2 // The dark theme is selected.
305 else -> 0 // The system default theme is selected.
308 // Set the current theme as the summary text for the preference.
309 webViewThemePreference.summary = webViewThemeEntriesStringArray[webViewThemeEntryNumber]
311 // Set the JavaScript icon.
312 if (javaScriptEnabled)
313 javaScriptPreference.setIcon(R.drawable.javascript_enabled)
315 javaScriptPreference.setIcon(R.drawable.privacy_mode)
317 // Set the cookies icon.
318 if (sharedPreferences.getBoolean(getString(R.string.cookies_key), false))
319 cookiesPreference.setIcon(R.drawable.cookies_enabled)
321 cookiesPreference.setIcon(R.drawable.cookies_disabled)
323 // Set the DOM storage icon.
324 if (javaScriptEnabled) { // JavaScript is enabled.
325 if (sharedPreferences.getBoolean(getString(R.string.dom_storage_key), false)) // DOM storage is enabled.
326 domStoragePreference.setIcon(R.drawable.dom_storage_enabled)
327 else // DOM storage is disabled.
328 domStoragePreference.setIcon(R.drawable.dom_storage_disabled)
329 } else { // JavaScript is disabled. DOM storage should be ghosted.
330 domStoragePreference.setIcon(R.drawable.dom_storage_ghosted)
333 // Set the save form data icon if API < 26. Save form data has no effect on API >= 26.
334 if (Build.VERSION.SDK_INT < 26) {
335 if (sharedPreferences.getBoolean(getString(R.string.save_form_data_key), false))
336 formDataPreference.setIcon(R.drawable.form_data_enabled)
338 formDataPreference.setIcon(R.drawable.form_data_disabled)
341 // Set the custom user agent icon.
342 if (customUserAgentPreference.isEnabled)
343 customUserAgentPreference.setIcon(R.drawable.custom_user_agent_enabled)
345 customUserAgentPreference.setIcon(R.drawable.custom_user_agent_ghosted)
347 // Set the incognito mode icon.
348 if (sharedPreferences.getBoolean(getString(R.string.incognito_mode_key), false))
349 incognitoModePreference.setIcon(R.drawable.incognito_mode_enabled)
351 incognitoModePreference.setIcon(R.drawable.incognito_mode_disabled)
353 // Set the allow screenshots icon.
354 if (sharedPreferences.getBoolean(getString(R.string.allow_screenshots_key), false))
355 allowScreenshotsPreference.setIcon(R.drawable.allow_screenshots_enabled)
357 allowScreenshotsPreference.setIcon(R.drawable.allow_screenshots_disabled)
359 // Set the EasyList icon.
360 if (sharedPreferences.getBoolean(getString(R.string.easylist_key), true))
361 easyListPreference.setIcon(R.drawable.block_ads_enabled)
363 easyListPreference.setIcon(R.drawable.block_ads_disabled)
365 // Set the EasyPrivacy icon.
366 if (sharedPreferences.getBoolean(getString(R.string.easyprivacy_key), true))
367 easyPrivacyPreference.setIcon(R.drawable.block_tracking_enabled)
369 easyPrivacyPreference.setIcon(R.drawable.block_tracking_disabled)
371 // Set the Fanboy lists icons.
372 if (fanboyAnnoyanceListEnabled) {
373 // Set the Fanboy annoyance list icon.
374 fanboyAnnoyanceListPreference.setIcon(R.drawable.social_media_enabled)
376 // Set the Fanboy social blocking list icon.
377 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_ghosted)
379 // Set the Fanboy annoyance list icon.
380 fanboyAnnoyanceListPreference.setIcon(R.drawable.social_media_disabled)
382 // Set the Fanboy social blocking list icon.
383 if (fanboySocialBlockingEnabled)
384 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_enabled)
386 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_disabled)
389 // Set the UltraList icon.
390 if (sharedPreferences.getBoolean(getString(R.string.ultralist_key), true))
391 ultraListPreference.setIcon(R.drawable.block_ads_enabled)
393 ultraListPreference.setIcon(R.drawable.block_ads_disabled)
395 // Set the UltraPrivacy icon.
396 if (sharedPreferences.getBoolean(getString(R.string.ultraprivacy_key), true))
397 ultraPrivacyPreference.setIcon(R.drawable.block_tracking_enabled)
399 ultraPrivacyPreference.setIcon(R.drawable.block_tracking_disabled)
401 // Set the block all third-party requests icon.
402 if (sharedPreferences.getBoolean(getString(R.string.block_all_third_party_requests), false))
403 blockAllThirdPartyRequestsPreference.setIcon(R.drawable.block_all_third_party_requests_enabled)
405 blockAllThirdPartyRequestsPreference.setIcon(R.drawable.block_all_third_party_requests_disabled)
407 // Set the Tracking Queries icon.
408 if (sharedPreferences.getBoolean(getString(R.string.tracking_queries_key), true))
409 trackingQueriesPreference.setIcon(R.drawable.modify_url_enabled)
411 trackingQueriesPreference.setIcon(R.drawable.modify_url_disabled)
413 // Set the AMP Redirects icon.
414 if (sharedPreferences.getBoolean(getString(R.string.amp_redirects_key), true))
415 ampRedirectsPreference.setIcon(R.drawable.modify_url_enabled)
417 ampRedirectsPreference.setIcon(R.drawable.modify_url_disabled)
419 // Set the search custom URL icon.
420 if (searchCustomURLPreference.isEnabled)
421 searchCustomURLPreference.setIcon(R.drawable.search_custom_enabled)
423 searchCustomURLPreference.setIcon(R.drawable.search_custom_ghosted)
425 // Set the proxy icons according to the theme and status.
426 if (proxyString == ProxyHelper.NONE) { // Proxying is disabled.
427 // Set the main proxy icon to be disabled.
428 proxyPreference.setIcon(R.drawable.proxy_disabled)
430 // Set the custom proxy URL icon to be ghosted.
431 proxyCustomUrlPreference.setIcon(R.drawable.proxy_ghosted)
432 } else { // Proxying is enabled.
433 // Set the main proxy icon to be enabled.
434 proxyPreference.setIcon(R.drawable.proxy_enabled)
436 // Set the custom proxy URL icon according to its status.
437 if (proxyCustomUrlPreference.isEnabled)
438 proxyCustomUrlPreference.setIcon(R.drawable.proxy_enabled)
440 proxyCustomUrlPreference.setIcon(R.drawable.proxy_ghosted)
443 // Set the full-screen browsing mode icons.
444 if (fullScreenBrowsingMode) { // Full-screen browsing mode is enabled.
445 // Set the full screen browsing mode preference icon.
446 fullScreenBrowsingModePreference.setIcon(R.drawable.full_screen_enabled)
448 // Set the hide app bar icon.
449 if (sharedPreferences.getBoolean(getString(R.string.hide_app_bar_key), true))
450 hideAppBarPreference.setIcon(R.drawable.app_bar_enabled)
452 hideAppBarPreference.setIcon(R.drawable.app_bar_disabled)
453 } else { // Full screen browsing mode is disabled.
455 fullScreenBrowsingModePreference.setIcon(R.drawable.full_screen_disabled)
456 hideAppBarPreference.setIcon(R.drawable.app_bar_ghosted)
459 // Set the clear everything icon.
460 if (clearEverything) {
461 clearEverythingPreference.setIcon(R.drawable.clear_everything_enabled)
463 clearEverythingPreference.setIcon(R.drawable.clear_everything_disabled)
466 // Set the clear cookies icon.
467 if (clearEverything || sharedPreferences.getBoolean(getString(R.string.clear_cookies_key), true))
468 clearCookiesPreference.setIcon(R.drawable.clear_cookies_enabled)
470 clearCookiesPreference.setIcon(R.drawable.clear_cookies_disabled)
472 // Set the clear DOM storage icon.
473 if (clearEverything || sharedPreferences.getBoolean(getString(R.string.clear_dom_storage_key), true))
474 clearDomStoragePreference.setIcon(R.drawable.clear_dom_storage_enabled)
476 clearDomStoragePreference.setIcon(R.drawable.clear_dom_storage_disabled)
478 // Set the clear form data icon if the API < 26. It has no effect on newer versions of Android.
479 if (Build.VERSION.SDK_INT < 26) {
480 if (clearEverything || sharedPreferences.getBoolean(getString(R.string.clear_form_data_key), true))
481 clearFormDataPreference.setIcon(R.drawable.clear_form_data_enabled)
483 clearFormDataPreference.setIcon(R.drawable.clear_form_data_disabled)
486 // Set the clear logcat icon.
487 if (clearEverything || sharedPreferences.getBoolean(getString(R.string.clear_logcat_key), true))
488 clearLogcatPreference.setIcon(R.drawable.clear_logcat_enabled)
490 clearLogcatPreference.setIcon(R.drawable.clear_logcat_disabled)
492 // Set the clear cache icon.
493 if (clearEverything || sharedPreferences.getBoolean(getString(R.string.clear_cache_key), true))
494 clearCachePreference.setIcon(R.drawable.clear_cache_enabled)
496 clearCachePreference.setIcon(R.drawable.clear_cache_disabled)
498 // Set the open intents in new tab icon.
499 if (sharedPreferences.getBoolean(getString(R.string.open_intents_in_new_tab_key), true))
500 openIntentsInNewTabPreference.setIcon(R.drawable.tab_enabled)
502 openIntentsInNewTabPreference.setIcon(R.drawable.tab_disabled)
504 // Set the swipe to refresh icon.
505 if (sharedPreferences.getBoolean(getString(R.string.swipe_to_refresh_key), true))
506 swipeToRefreshPreference.setIcon(R.drawable.refresh_enabled)
508 swipeToRefreshPreference.setIcon(R.drawable.refresh_disabled)
510 // Set the download with external app icon.
511 if (sharedPreferences.getBoolean(getString(R.string.download_with_external_app_key), false))
512 downloadWithExternalAppPreference.setIcon(R.drawable.download_with_external_app_enabled)
514 downloadWithExternalAppPreference.setIcon(R.drawable.download_with_external_app_disabled)
516 // Set the scroll app bar icon.
517 if (sharedPreferences.getBoolean(getString(R.string.scroll_app_bar_key), true))
518 scrollAppBarPreference.setIcon(R.drawable.app_bar_enabled)
520 scrollAppBarPreference.setIcon(R.drawable.app_bar_disabled)
522 // Set the bottom app bar icon.
523 if (sharedPreferences.getBoolean(getString(R.string.bottom_app_bar_key), false))
524 bottomAppBarPreference.setIcon(R.drawable.bottom_app_bar_enabled)
526 bottomAppBarPreference.setIcon(R.drawable.bottom_app_bar_disabled)
528 // Set the display additional app bar icons icon.
529 if (sharedPreferences.getBoolean(getString(R.string.display_additional_app_bar_icons_key), false))
530 displayAdditionalAppBarIconsPreference.setIcon(R.drawable.more_enabled)
532 displayAdditionalAppBarIconsPreference.setIcon(R.drawable.more_disabled)
534 // Set the WebView theme icon.
535 if (webViewThemePreference.isEnabled) { // The WebView theme preference is enabled.
536 when (webViewThemeEntryNumber) {
537 // The system default WebView theme is selected.
539 // Get the current theme status.
540 val currentThemeStatus = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
542 // Set the icon according to the app theme.
543 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO)
544 webViewThemePreference.setIcon(R.drawable.webview_light_theme)
546 webViewThemePreference.setIcon(R.drawable.webview_dark_theme)
549 // The light WebView theme is selected.
552 webViewThemePreference.setIcon(R.drawable.webview_light_theme)
555 // The dark WebView theme is selected.
558 webViewThemePreference.setIcon(R.drawable.webview_dark_theme)
561 } else { // The WebView theme preference is disabled.
562 webViewThemePreference.setIcon(R.drawable.webview_theme_ghosted)
565 // Set the wide viewport icon.
566 if (sharedPreferences.getBoolean(getString(R.string.wide_viewport_key), true))
567 wideViewportPreference.setIcon(R.drawable.wide_viewport_enabled)
569 wideViewportPreference.setIcon(R.drawable.wide_viewport_disabled)
571 // Set the display webpage images icon.
572 if (sharedPreferences.getBoolean(getString(R.string.display_webpage_images_key), true))
573 displayWebpageImagesPreference.setIcon(R.drawable.images_enabled)
575 displayWebpageImagesPreference.setIcon(R.drawable.images_disabled)
578 // The listener should be unregistered when the app is paused.
579 override fun onPause() {
580 // Run the default commands.
583 // Get a handle for the shared preferences.
584 val sharedPreferences = preferenceScreen.sharedPreferences!!
586 // Unregister the shared preference listener.
587 sharedPreferences.unregisterOnSharedPreferenceChangeListener(sharedPreferenceChangeListener)
590 // The listener should be re-registered when the app is resumed.
591 override fun onResume() {
592 // Run the default commands.
595 // Get a new shared preference change listener.
596 sharedPreferenceChangeListener = getSharedPreferenceChangeListener()
598 // Get a handle for the shared preferences.
599 val sharedPreferences = preferenceScreen.sharedPreferences!!
601 // Re-register the shared preference listener.
602 sharedPreferences.registerOnSharedPreferenceChangeListener(sharedPreferenceChangeListener)
604 // Restore the scroll position if the fragment has been restarted.
605 if (fragmentRestarted) {
606 // Reset the fragment restarted flag.
607 fragmentRestarted = false
609 // Set the scroll position.
610 listView.smoothScrollBy(0, scrollY)
614 override fun onSaveInstanceState(savedInstanceState: Bundle) {
615 // Run the default commands.
616 super.onSaveInstanceState(savedInstanceState)
618 // Save the scroll position.
619 savedInstanceState.putInt(SCROLL_Y, listView.computeVerticalScrollOffset())
622 private fun getSharedPreferenceChangeListener(): OnSharedPreferenceChangeListener {
623 // Return the shared preference change listener.
624 return OnSharedPreferenceChangeListener { sharedPreferences: SharedPreferences, key: String? ->
626 getString(R.string.javascript_key) -> {
627 // Update the icons and the DOM storage preference status.
628 if (sharedPreferences.getBoolean(getString(R.string.javascript_key), false)) { // The JavaScript preference is enabled.
629 // Update the icon for the JavaScript preference.
630 javaScriptPreference.setIcon(R.drawable.javascript_enabled)
632 // Update the status of the DOM storage preference.
633 domStoragePreference.isEnabled = true
635 // Update the icon for the DOM storage preference.
636 if (sharedPreferences.getBoolean(getString(R.string.dom_storage_key), false))
637 domStoragePreference.setIcon(R.drawable.dom_storage_enabled)
639 domStoragePreference.setIcon(R.drawable.dom_storage_disabled)
640 } else { // The JavaScript preference is disabled.
641 // Update the icon for the JavaScript preference.
642 javaScriptPreference.setIcon(R.drawable.privacy_mode)
644 // Update the status of the DOM storage preference.
645 domStoragePreference.isEnabled = false
647 // Set the icon for DOM storage preference to be ghosted.
648 domStoragePreference.setIcon(R.drawable.dom_storage_ghosted)
652 getString(R.string.cookies_key) -> {
654 if (sharedPreferences.getBoolean(getString(R.string.cookies_key), false))
655 cookiesPreference.setIcon(R.drawable.cookies_enabled)
657 cookiesPreference.setIcon(R.drawable.cookies_disabled)
660 getString(R.string.dom_storage_key) -> {
662 if (sharedPreferences.getBoolean(getString(R.string.dom_storage_key), false))
663 domStoragePreference.setIcon(R.drawable.dom_storage_enabled)
665 domStoragePreference.setIcon(R.drawable.dom_storage_disabled)
668 getString(R.string.save_form_data_key) -> { // Saved form data can be removed once the minimum API >= 26.
670 if (sharedPreferences.getBoolean(getString(R.string.save_form_data_key), false))
671 formDataPreference.setIcon(R.drawable.form_data_enabled)
673 formDataPreference.setIcon(R.drawable.form_data_disabled)
676 getString(R.string.user_agent_key) -> {
677 // Get the new user agent name.
678 val newUserAgentName = sharedPreferences.getString(getString(R.string.user_agent_key), getString(R.string.user_agent_default_value))
680 // Get the array position for the new user agent name.
681 val newUserAgentArrayPosition = userAgentNamesArray.getPosition(newUserAgentName)
683 // Get the translated new user agent name.
684 val translatedNewUserAgentName = translatedUserAgentNamesArray[newUserAgentArrayPosition]
686 // Populate the user agent summary.
687 when (newUserAgentArrayPosition) {
688 SETTINGS_WEBVIEW_DEFAULT_USER_AGENT -> {
689 // Get the user agent text from the webview (which changes based on the version of Android and WebView installed).
690 userAgentPreference.summary = "$translatedNewUserAgentName:\n$defaultUserAgent"
692 // Disable the custom user agent preference.
693 customUserAgentPreference.isEnabled = false
695 // Set the custom user agent preference icon.
696 customUserAgentPreference.setIcon(R.drawable.custom_user_agent_ghosted)
699 SETTINGS_CUSTOM_USER_AGENT -> {
700 // Set the summary text.
701 userAgentPreference.setSummary(R.string.custom_user_agent)
703 // Enable the custom user agent preference.
704 customUserAgentPreference.isEnabled = true
706 // Set the custom user agent preference icon.
707 customUserAgentPreference.setIcon(R.drawable.custom_user_agent_enabled)
711 // Get the user agent summary from the user agent data array.
712 userAgentPreference.summary = "$translatedNewUserAgentName:\n${userAgentDataArray[newUserAgentArrayPosition]}"
714 // Disable the custom user agent preference.
715 customUserAgentPreference.isEnabled = false
717 // Set the custom user agent preference icon.
718 customUserAgentPreference.setIcon(R.drawable.custom_user_agent_ghosted)
723 getString(R.string.custom_user_agent_key) -> {
724 // Set the new custom user agent as the summary text for the preference.
725 customUserAgentPreference.summary = sharedPreferences.getString(getString(R.string.custom_user_agent_key), getString(R.string.custom_user_agent_default_value))
728 getString(R.string.incognito_mode_key) -> {
730 if (sharedPreferences.getBoolean(getString(R.string.incognito_mode_key), false))
731 incognitoModePreference.setIcon(R.drawable.incognito_mode_enabled)
733 incognitoModePreference.setIcon(R.drawable.incognito_mode_disabled)
736 getString(R.string.allow_screenshots_key) -> {
738 if (sharedPreferences.getBoolean(getString(R.string.allow_screenshots_key), false))
739 allowScreenshotsPreference.setIcon(R.drawable.allow_screenshots_enabled)
741 allowScreenshotsPreference.setIcon(R.drawable.allow_screenshots_disabled)
743 // Restart Privacy Browser.
744 restartPrivacyBrowser()
747 getString(R.string.easylist_key) -> {
749 if (sharedPreferences.getBoolean(getString(R.string.easylist_key), true))
750 easyListPreference.setIcon(R.drawable.block_ads_enabled)
752 easyListPreference.setIcon(R.drawable.block_ads_disabled)
755 getString(R.string.easyprivacy_key) -> {
757 if (sharedPreferences.getBoolean(getString(R.string.easyprivacy_key), true))
758 easyPrivacyPreference.setIcon(R.drawable.block_tracking_enabled)
760 easyPrivacyPreference.setIcon(R.drawable.block_tracking_disabled)
763 getString(R.string.fanboys_annoyance_list_key) -> {
764 // Get the current Fanboy settings.
765 val currentFanboyAnnoyanceList = sharedPreferences.getBoolean(getString(R.string.fanboys_annoyance_list_key), true)
766 val currentFanboySocialBlockingList = sharedPreferences.getBoolean(getString(R.string.fanboys_social_blocking_list_key), true)
768 // Update the Fanboy icons.
769 if (currentFanboyAnnoyanceList) { // Fanboy's annoyance list is enabled.
770 // Update the Fanboy's annoyance list icon.
771 fanboyAnnoyanceListPreference.setIcon(R.drawable.social_media_enabled)
773 // Update the Fanboy's social blocking list icon.
774 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_ghosted)
775 } else { // Fanboy's annoyance list is disabled.
776 // Update the Fanboy's annoyance list icon.
777 fanboyAnnoyanceListPreference.setIcon(R.drawable.social_media_disabled)
779 // Update the Fanboy's social blocking list icon.
780 if (currentFanboySocialBlockingList)
781 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_enabled)
783 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_disabled)
786 // Only enable Fanboy's social blocking list preference if Fanboy's annoyance list preference is disabled.
787 fanboySocialBlockingListPreference.isEnabled = !currentFanboyAnnoyanceList
790 getString(R.string.fanboys_social_blocking_list_key) -> {
792 if (sharedPreferences.getBoolean(getString(R.string.fanboys_social_blocking_list_key), true))
793 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_enabled)
795 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_disabled)
798 getString(R.string.ultralist_key) -> {
800 if (sharedPreferences.getBoolean(getString(R.string.ultralist_key), true))
801 ultraListPreference.setIcon(R.drawable.block_ads_enabled)
803 ultraListPreference.setIcon(R.drawable.block_ads_disabled)
806 getString(R.string.ultraprivacy_key) -> {
808 if (sharedPreferences.getBoolean(getString(R.string.ultraprivacy_key), true))
809 ultraPrivacyPreference.setIcon(R.drawable.block_tracking_enabled)
811 ultraPrivacyPreference.setIcon(R.drawable.block_tracking_disabled)
814 getString(R.string.block_all_third_party_requests_key) -> {
816 if (sharedPreferences.getBoolean(getString(R.string.block_all_third_party_requests_key), false)) {
817 blockAllThirdPartyRequestsPreference.setIcon(R.drawable.block_all_third_party_requests_enabled)
819 blockAllThirdPartyRequestsPreference.setIcon(R.drawable.block_all_third_party_requests_disabled)
823 getString(R.string.tracking_queries_key) -> {
825 if (sharedPreferences.getBoolean(getString(R.string.tracking_queries_key), true))
826 trackingQueriesPreference.setIcon(R.drawable.modify_url_enabled)
828 trackingQueriesPreference.setIcon(R.drawable.modify_url_disabled)
831 getString(R.string.amp_redirects_key) -> {
833 if (sharedPreferences.getBoolean(getString(R.string.amp_redirects_key), true))
834 ampRedirectsPreference.setIcon(R.drawable.modify_url_enabled)
836 ampRedirectsPreference.setIcon(R.drawable.modify_url_disabled)
839 getString(R.string.search_key) -> {
840 // Store the new search string.
841 val newSearchString = sharedPreferences.getString(getString(R.string.search_key), getString(R.string.search_default_value))
843 // Update the search and search custom URL preferences.
844 if (newSearchString == getString(R.string.custom_url_item)) { // A custom URL is selected.
845 // Set the summary text to `R.string.custom_url`, which is translated.
846 searchPreference.setSummary(R.string.custom_url)
848 // Enable the search custom URL preference.
849 searchCustomURLPreference.isEnabled = true
851 // Set the search custom URL preference icon.
852 searchCustomURLPreference.setIcon(R.drawable.search_custom_enabled)
853 } else { // A custom URL is not selected.
854 // Set the summary text to the new search string.
855 searchPreference.summary = newSearchString
857 // Disable the search custom URL Preference.
858 searchCustomURLPreference.isEnabled = false
860 // Set the search custom URL preference icon.
861 searchCustomURLPreference.setIcon(R.drawable.search_custom_ghosted)
865 getString(R.string.search_custom_url_key) -> {
866 // Set the new search custom URL as the summary text for the preference.
867 searchCustomURLPreference.summary = sharedPreferences.getString(getString(R.string.search_custom_url_key), getString(R.string.search_custom_url_default_value))
870 getString(R.string.proxy_key) -> {
871 // Get the current proxy string.
872 val currentProxyString = sharedPreferences.getString(getString(R.string.proxy_key), getString(R.string.proxy_default_value))
874 // Update the proxy preference summary text.
875 proxyPreference.summary = when (currentProxyString) {
876 ProxyHelper.NONE -> getString(R.string.no_proxy_enabled)
877 ProxyHelper.TOR -> getString(R.string.tor_enabled)
878 ProxyHelper.I2P -> getString(R.string.i2p_enabled)
879 ProxyHelper.CUSTOM -> getString(R.string.custom_proxy)
880 else -> getString(R.string.no_proxy_enabled)
883 // Update the status of the custom URL preference.
884 proxyCustomUrlPreference.isEnabled = currentProxyString == ProxyHelper.CUSTOM
887 if (currentProxyString == ProxyHelper.NONE) { // Proxying is disabled.
888 // Set the main proxy icon to be disabled
889 proxyPreference.setIcon(R.drawable.proxy_disabled)
891 // Set the custom proxy URL icon to be ghosted.
892 proxyCustomUrlPreference.setIcon(R.drawable.proxy_ghosted)
893 } else { // Proxying is enabled.
894 // Set the main proxy icon to be enabled.
895 proxyPreference.setIcon(R.drawable.proxy_enabled)
897 /// Set the custom proxy URL icon according to its status.
898 if (proxyCustomUrlPreference.isEnabled)
899 proxyCustomUrlPreference.setIcon(R.drawable.proxy_enabled)
901 proxyCustomUrlPreference.setIcon(R.drawable.proxy_ghosted)
905 getString(R.string.proxy_custom_url_key) -> {
906 // Set the summary text for the proxy custom URL.
907 proxyCustomUrlPreference.summary = sharedPreferences.getString(getString(R.string.proxy_custom_url_key), getString(R.string.proxy_custom_url_default_value))
910 getString(R.string.full_screen_browsing_mode_key) -> {
912 if (sharedPreferences.getBoolean(getString(R.string.full_screen_browsing_mode_key), false)) { // Full screen browsing is enabled.
913 // Set the full screen browsing mode preference icon.
914 fullScreenBrowsingModePreference.setIcon(R.drawable.full_screen_enabled)
916 // Set the hide app bar preference icon.
917 if (sharedPreferences.getBoolean(getString(R.string.hide_app_bar_key), true))
918 hideAppBarPreference.setIcon(R.drawable.app_bar_enabled)
920 hideAppBarPreference.setIcon(R.drawable.app_bar_disabled)
921 } else { // Full screen browsing is disabled.
923 fullScreenBrowsingModePreference.setIcon(R.drawable.full_screen_disabled)
924 hideAppBarPreference.setIcon(R.drawable.app_bar_ghosted)
928 getString(R.string.hide_app_bar_key) -> {
930 if (sharedPreferences.getBoolean(getString(R.string.hide_app_bar_key), true))
931 hideAppBarPreference.setIcon(R.drawable.app_bar_enabled)
933 hideAppBarPreference.setIcon(R.drawable.app_bar_disabled)
936 getString(R.string.clear_everything_key) -> {
937 // Store the new clear everything status
938 val newClearEverythingBoolean = sharedPreferences.getBoolean(getString(R.string.clear_everything_key), true)
940 // Update the status of the clear and exit preferences.
941 clearCookiesPreference.isEnabled = !newClearEverythingBoolean
942 clearDomStoragePreference.isEnabled = !newClearEverythingBoolean
943 clearFormDataPreference.isEnabled = !newClearEverythingBoolean // Clear form data can be removed once the minimum API >= 26.
944 clearLogcatPreference.isEnabled = !newClearEverythingBoolean
945 clearCachePreference.isEnabled = !newClearEverythingBoolean
947 // Update the clear everything preference icon.
948 if (newClearEverythingBoolean)
949 clearEverythingPreference.setIcon(R.drawable.clear_everything_enabled)
951 clearEverythingPreference.setIcon(R.drawable.clear_everything_disabled)
953 // Update the clear cookies preference icon.
954 if (newClearEverythingBoolean || sharedPreferences.getBoolean(getString(R.string.clear_cookies_key), true))
955 clearCookiesPreference.setIcon(R.drawable.clear_cookies_enabled)
957 clearCookiesPreference.setIcon(R.drawable.clear_cookies_disabled)
959 // Update the clear dom storage preference icon.
960 if (newClearEverythingBoolean || sharedPreferences.getBoolean(getString(R.string.clear_dom_storage_key), true))
961 clearDomStoragePreference.setIcon(R.drawable.clear_dom_storage_enabled)
963 clearDomStoragePreference.setIcon(R.drawable.clear_dom_storage_disabled)
965 // Update the clear form data preference icon if the API < 26.
966 if (Build.VERSION.SDK_INT < 26) {
967 if (newClearEverythingBoolean || sharedPreferences.getBoolean(getString(R.string.clear_form_data_key), true))
968 clearFormDataPreference.setIcon(R.drawable.clear_form_data_enabled)
970 clearFormDataPreference.setIcon(R.drawable.clear_form_data_disabled)
973 // Update the clear logcat preference icon.
974 if (newClearEverythingBoolean || sharedPreferences.getBoolean(getString(R.string.clear_logcat_key), true))
975 clearLogcatPreference.setIcon(R.drawable.clear_logcat_enabled)
977 clearLogcatPreference.setIcon(R.drawable.clear_logcat_disabled)
979 // Update the clear cache preference icon.
980 if (newClearEverythingBoolean || sharedPreferences.getBoolean(getString(R.string.clear_cache_key), true))
981 clearCachePreference.setIcon(R.drawable.clear_cache_enabled)
983 clearCachePreference.setIcon(R.drawable.clear_cache_disabled)
986 getString(R.string.clear_cookies_key) -> {
988 if (sharedPreferences.getBoolean(getString(R.string.clear_cookies_key), true))
989 clearCookiesPreference.setIcon(R.drawable.clear_cookies_enabled)
991 clearCookiesPreference.setIcon(R.drawable.clear_cookies_disabled)
994 getString(R.string.clear_dom_storage_key) -> {
996 if (sharedPreferences.getBoolean(getString(R.string.clear_dom_storage_key), true))
997 clearDomStoragePreference.setIcon(R.drawable.clear_dom_storage_enabled)
999 clearDomStoragePreference.setIcon(R.drawable.clear_dom_storage_disabled)
1002 getString(R.string.clear_form_data_key) -> {
1004 if (sharedPreferences.getBoolean(getString(R.string.clear_form_data_key), true))
1005 clearFormDataPreference.setIcon(R.drawable.clear_form_data_enabled)
1007 clearFormDataPreference.setIcon(R.drawable.clear_form_data_disabled)
1010 getString(R.string.clear_logcat_key) -> {
1012 if (sharedPreferences.getBoolean(getString(R.string.clear_logcat_key), true))
1013 clearLogcatPreference.setIcon(R.drawable.clear_logcat_enabled)
1015 clearLogcatPreference.setIcon(R.drawable.clear_logcat_disabled)
1018 getString(R.string.clear_cache_key) -> {
1020 if (sharedPreferences.getBoolean(getString(R.string.clear_cache_key), true))
1021 clearCachePreference.setIcon(R.drawable.clear_cache_enabled)
1023 clearCachePreference.setIcon(R.drawable.clear_cache_disabled)
1026 getString(R.string.homepage_key) -> {
1027 // Set the new homepage URL as the summary text for the Homepage preference.
1028 homepagePreference.summary = sharedPreferences.getString(getString(R.string.homepage_key), getString(R.string.homepage_default_value))
1031 getString(R.string.font_size_key) -> {
1032 // Update the font size summary text.
1033 fontSizePreference.summary = sharedPreferences.getString(getString(R.string.font_size_key), getString(R.string.font_size_default_value)) + "%"
1036 getString(R.string.open_intents_in_new_tab_key) -> {
1038 if (sharedPreferences.getBoolean(getString(R.string.open_intents_in_new_tab_key), true))
1039 openIntentsInNewTabPreference.setIcon(R.drawable.tab_enabled)
1041 openIntentsInNewTabPreference.setIcon(R.drawable.tab_disabled)
1044 getString(R.string.swipe_to_refresh_key) -> {
1046 if (sharedPreferences.getBoolean(getString(R.string.swipe_to_refresh_key), true))
1047 swipeToRefreshPreference.setIcon(R.drawable.refresh_enabled)
1049 swipeToRefreshPreference.setIcon(R.drawable.refresh_disabled)
1052 getString(R.string.download_with_external_app_key) -> {
1054 if (sharedPreferences.getBoolean(getString(R.string.download_with_external_app_key), false))
1055 downloadWithExternalAppPreference.setIcon(R.drawable.download_with_external_app_enabled)
1057 downloadWithExternalAppPreference.setIcon(R.drawable.download_with_external_app_disabled)
1060 getString(R.string.scroll_app_bar_key) -> {
1062 if (sharedPreferences.getBoolean(getString(R.string.scroll_app_bar_key), true))
1063 scrollAppBarPreference.setIcon(R.drawable.app_bar_enabled)
1065 scrollAppBarPreference.setIcon(R.drawable.app_bar_disabled)
1068 getString(R.string.bottom_app_bar_key) -> {
1070 if (sharedPreferences.getBoolean(getString(R.string.bottom_app_bar_key), false))
1071 bottomAppBarPreference.setIcon(R.drawable.bottom_app_bar_enabled)
1073 bottomAppBarPreference.setIcon(R.drawable.bottom_app_bar_disabled)
1075 // Restart Privacy Browser.
1076 restartPrivacyBrowser()
1079 getString(R.string.display_additional_app_bar_icons_key) -> {
1081 if (sharedPreferences.getBoolean(getString(R.string.display_additional_app_bar_icons_key), false))
1082 displayAdditionalAppBarIconsPreference.setIcon(R.drawable.more_enabled)
1084 displayAdditionalAppBarIconsPreference.setIcon(R.drawable.more_disabled)
1086 // Restart Privacy Browser.
1087 restartPrivacyBrowser()
1090 getString(R.string.app_theme_key) -> {
1091 // Get the app theme entry number that matches the current app theme.
1092 val appThemeEntryNumber: Int = when (sharedPreferences.getString(getString(R.string.app_theme_key), getString(R.string.app_theme_default_value))) {
1093 appThemeEntryValuesStringArray[1] -> 1 // The light theme is selected.
1094 appThemeEntryValuesStringArray[2] -> 2 // The dark theme is selected.
1095 else -> 0 // The system default theme is selected.
1098 // Update the system according to the new theme.
1099 when (appThemeEntryNumber) {
1100 0 -> { // The system default theme is selected.
1101 // Update the theme preference summary text.
1102 appThemePreference.summary = appThemeEntriesStringArray[0]
1104 // Apply the new theme.
1105 if (Build.VERSION.SDK_INT >= 28) { // The system default theme is supported.
1106 // Follow the system default theme.
1107 AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
1108 } else { // The system default theme is not supported.
1109 // Follow the battery saver mode.
1110 AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_AUTO_BATTERY)
1114 1 -> { // The light theme is selected.
1115 // Update the theme preference summary text.
1116 appThemePreference.summary = appThemeEntriesStringArray[1]
1118 // Apply the new theme.
1119 AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
1122 2 -> { // The dark theme is selected.
1123 // Update the theme preference summary text.
1124 appThemePreference.summary = appThemeEntriesStringArray[2]
1126 // Apply the new theme.
1127 AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
1131 // Enable the WebView theme preference if the app theme is not set to light. Google does not allow light themes to display dark WebViews.
1132 webViewThemePreference.isEnabled = (appThemeEntryNumber != 1)
1134 // Get the webView theme entry number that matches the new WebView theme.
1135 val webViewThemeEntryNumber: Int = when (sharedPreferences.getString(getString(R.string.webview_theme_key), getString(R.string.webview_theme_default_value))) {
1136 webViewThemeEntriesStringArray[1] -> 1 // The light theme is selected.
1137 webViewThemeEntryValuesStringArray[2] -> 2 // The dark theme is selected.
1138 else -> 0 // The system default theme is selected.
1141 // Update the WebView theme icon.
1142 if (webViewThemePreference.isEnabled) { // The WebView theme preference is enabled.
1143 when (webViewThemeEntryNumber) {
1144 // The system default WebView theme is selected.
1146 // Get the current theme status.
1147 val currentThemeStatus = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
1149 // Set the icon according to the app theme.
1150 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO)
1151 webViewThemePreference.setIcon(R.drawable.webview_light_theme)
1153 webViewThemePreference.setIcon(R.drawable.webview_dark_theme)
1156 // The light WebView theme is selected.
1159 webViewThemePreference.setIcon(R.drawable.webview_light_theme)
1162 // The dark WebView theme is selected.
1165 webViewThemePreference.setIcon(R.drawable.webview_dark_theme)
1168 } else { // The WebView theme preference is disabled.
1169 webViewThemePreference.setIcon(R.drawable.webview_theme_ghosted)
1173 getString(R.string.webview_theme_key) -> {
1174 // Get the webView theme entry number that matches the new WebView theme.
1175 val newWebViewThemeEntryNumber: Int = when (sharedPreferences.getString(getString(R.string.webview_theme_key), getString(R.string.webview_theme_default_value))) {
1176 webViewThemeEntriesStringArray[1] -> 1 // The light theme is selected.
1177 webViewThemeEntryValuesStringArray[2] -> 2 // The dark theme is selected.
1178 else -> 0 // The system default theme is selected.
1181 // Update the WebView theme icon.
1182 when (newWebViewThemeEntryNumber) {
1183 // The system default WebView theme is selected.
1185 // Get the current theme status.
1186 val currentThemeStatus = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
1189 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO)
1190 webViewThemePreference.setIcon(R.drawable.webview_light_theme)
1192 webViewThemePreference.setIcon(R.drawable.webview_dark_theme)
1195 // The light WebView theme is selected.
1198 webViewThemePreference.setIcon(R.drawable.webview_light_theme)
1201 // The dark WebView theme is selected.
1204 webViewThemePreference.setIcon(R.drawable.webview_dark_theme)
1208 // Set the current theme as the summary text for the preference.
1209 webViewThemePreference.summary = webViewThemeEntriesStringArray[newWebViewThemeEntryNumber]
1212 getString(R.string.wide_viewport_key) -> {
1214 if (sharedPreferences.getBoolean(getString(R.string.wide_viewport_key), true))
1215 wideViewportPreference.setIcon(R.drawable.wide_viewport_enabled)
1217 wideViewportPreference.setIcon(R.drawable.wide_viewport_disabled)
1220 getString(R.string.display_webpage_images_key) -> {
1222 if (sharedPreferences.getBoolean(getString(R.string.display_webpage_images_key), true))
1223 displayWebpageImagesPreference.setIcon(R.drawable.images_enabled)
1225 displayWebpageImagesPreference.setIcon(R.drawable.images_disabled)
1231 private fun restartPrivacyBrowser() {
1232 // Create an intent to restart Privacy Browser.
1233 val restartIntent = requireActivity().parentActivityIntent!!
1235 // `Intent.FLAG_ACTIVITY_CLEAR_TASK` removes all activities from the stack. It requires `Intent.FLAG_ACTIVITY_NEW_TASK`.
1236 restartIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
1238 // Create a handler to restart the activity.
1239 val restartHandler = Handler(Looper.getMainLooper())
1241 // Create a runnable to restart the activity.
1242 val restartRunnable = Runnable {
1243 // Restart the activity.
1244 startActivity(restartIntent)
1246 // Kill this instance of Privacy Browser. Otherwise, the app exhibits sporadic behavior after the restart.
1250 // Restart the activity after 400 milliseconds, so that the app has enough time to save the change to the preference.
1251 restartHandler.postDelayed(restartRunnable, 400)