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 displayUnderCutoutsPreference: Preference
86 private lateinit var homepagePreference: Preference
87 private lateinit var incognitoModePreference: Preference
88 private lateinit var javaScriptPreference: Preference
89 private lateinit var openIntentsInNewTabPreference: Preference
90 private lateinit var proxyCustomUrlPreference: Preference
91 private lateinit var proxyPreference: Preference
92 private lateinit var scrollAppBarPreference: Preference
93 private lateinit var searchCustomURLPreference: Preference
94 private lateinit var searchPreference: Preference
95 private lateinit var sharedPreferenceChangeListener: OnSharedPreferenceChangeListener
96 private lateinit var swipeToRefreshPreference: Preference
97 private lateinit var trackingQueriesPreference: Preference
98 private lateinit var translatedUserAgentNamesArray: Array<String>
99 private lateinit var ultraListPreference: Preference
100 private lateinit var ultraPrivacyPreference: Preference
101 private lateinit var userAgentDataArray: Array<String>
102 private lateinit var userAgentPreference: Preference
103 private lateinit var userAgentNamesArray: ArrayAdapter<CharSequence>
104 private lateinit var webViewThemeEntriesStringArray: Array<String>
105 private lateinit var webViewThemeEntryValuesStringArray: Array<String>
106 private lateinit var webViewThemePreference: Preference
107 private lateinit var wideViewportPreference: Preference
109 override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
110 // Check if the fragment has been restarted.
111 if (savedInstanceState != null) {
112 // Set the fragment restored flag.
113 fragmentRestarted = true
115 // Save the scroll Y.
116 scrollY = savedInstanceState.getInt(SCROLL_Y)
119 // Load the preferences from the XML file.
120 setPreferencesFromResource(R.xml.preferences, rootKey)
122 // Get a handle for the shared preferences.
123 val sharedPreferences = preferenceScreen.sharedPreferences!!
125 // Get handles for the preferences.
126 javaScriptPreference = findPreference(getString(R.string.javascript_key))!!
127 cookiesPreference = findPreference(getString(R.string.cookies_key))!!
128 domStoragePreference = findPreference(getString(R.string.dom_storage_key))!!
129 formDataPreference = findPreference(getString(R.string.save_form_data_key))!! // The form data preference can be removed once the minimum API >= 26.
130 userAgentPreference = findPreference(getString(R.string.user_agent_key))!!
131 customUserAgentPreference = findPreference(getString(R.string.custom_user_agent_key))!!
132 incognitoModePreference = findPreference(getString(R.string.incognito_mode_key))!!
133 allowScreenshotsPreference = findPreference(getString(R.string.allow_screenshots_key))!!
134 easyListPreference = findPreference(getString(R.string.easylist_key))!!
135 easyPrivacyPreference = findPreference(getString(R.string.easyprivacy_key))!!
136 fanboyAnnoyanceListPreference = findPreference(getString(R.string.fanboys_annoyance_list_key))!!
137 fanboySocialBlockingListPreference = findPreference(getString(R.string.fanboys_social_blocking_list_key))!!
138 ultraListPreference = findPreference(getString(R.string.ultralist_key))!!
139 ultraPrivacyPreference = findPreference(getString(R.string.ultraprivacy_key))!!
140 blockAllThirdPartyRequestsPreference = findPreference(getString(R.string.block_all_third_party_requests_key))!!
141 trackingQueriesPreference = findPreference(getString(R.string.tracking_queries_key))!!
142 ampRedirectsPreference = findPreference(getString(R.string.amp_redirects_key))!!
143 searchPreference = findPreference(getString(R.string.search_key))!!
144 searchCustomURLPreference = findPreference(getString(R.string.search_custom_url_key))!!
145 proxyPreference = findPreference(getString(R.string.proxy_key))!!
146 proxyCustomUrlPreference = findPreference(getString(R.string.proxy_custom_url_key))!!
147 fullScreenBrowsingModePreference = findPreference(getString(R.string.full_screen_browsing_mode_key))!!
148 hideAppBarPreference = findPreference(getString(R.string.hide_app_bar_key))!!
149 displayUnderCutoutsPreference = findPreference(getString(R.string.display_under_cutouts_key))!!
150 clearEverythingPreference = findPreference(getString(R.string.clear_everything_key))!!
151 clearCookiesPreference = findPreference(getString(R.string.clear_cookies_key))!!
152 clearDomStoragePreference = findPreference(getString(R.string.clear_dom_storage_key))!!
153 clearFormDataPreference = findPreference(getString(R.string.clear_form_data_key))!! // The clear form data preference can be removed once the minimum API >= 26.
154 clearLogcatPreference = findPreference(getString(R.string.clear_logcat_key))!!
155 clearCachePreference = findPreference(getString(R.string.clear_cache_key))!!
156 homepagePreference = findPreference(getString(R.string.homepage_key))!!
157 fontSizePreference = findPreference(getString(R.string.font_size_key))!!
158 openIntentsInNewTabPreference = findPreference(getString(R.string.open_intents_in_new_tab_key))!!
159 swipeToRefreshPreference = findPreference(getString(R.string.swipe_to_refresh_key))!!
160 downloadWithExternalAppPreference = findPreference(getString(R.string.download_with_external_app_key))!!
161 scrollAppBarPreference = findPreference(getString(R.string.scroll_app_bar_key))!!
162 bottomAppBarPreference = findPreference(getString(R.string.bottom_app_bar_key))!!
163 displayAdditionalAppBarIconsPreference = findPreference(getString(R.string.display_additional_app_bar_icons_key))!!
164 appThemePreference = findPreference(getString(R.string.app_theme_key))!!
165 webViewThemePreference = findPreference(getString(R.string.webview_theme_key))!!
166 wideViewportPreference = findPreference(getString(R.string.wide_viewport_key))!!
167 displayWebpageImagesPreference = findPreference(getString(R.string.display_webpage_images_key))!!
169 // Set the preference dependencies.
170 domStoragePreference.dependency = getString(R.string.javascript_key)
171 hideAppBarPreference.dependency = getString(R.string.full_screen_browsing_mode_key)
173 // Get strings from the preferences.
174 val userAgentName = sharedPreferences.getString(getString(R.string.user_agent_key), getString(R.string.user_agent_default_value))
175 val searchString = sharedPreferences.getString(getString(R.string.search_key), getString(R.string.search_default_value))
176 val proxyString = sharedPreferences.getString(getString(R.string.proxy_key), getString(R.string.proxy_default_value))
178 // Get booleans that are used in multiple places from the preferences.
179 val javaScriptEnabled = sharedPreferences.getBoolean(getString(R.string.javascript_key), false)
180 val fanboyAnnoyanceListEnabled = sharedPreferences.getBoolean(getString(R.string.fanboys_annoyance_list_key), true)
181 val fanboySocialBlockingEnabled = sharedPreferences.getBoolean(getString(R.string.fanboys_social_blocking_list_key), true)
182 val fullScreenBrowsingMode = sharedPreferences.getBoolean(getString(R.string.full_screen_browsing_mode_key), false)
183 val clearEverything = sharedPreferences.getBoolean(getString(R.string.clear_everything_key), true)
185 // Remove the form data preferences if the API is >= 26 as they no longer do anything.
186 if (Build.VERSION.SDK_INT >= 26) {
187 // Get handles for the categories.
188 val privacyCategory = findPreference<PreferenceCategory>(getString(R.string.privacy_category_key))!!
189 val clearAndExitCategory = findPreference<PreferenceCategory>(getString(R.string.clear_and_exit_category_key))!!
191 // Remove the form data preferences.
192 privacyCategory.removePreference(formDataPreference)
193 clearAndExitCategory.removePreference(clearFormDataPreference)
196 // Only enable Fanboy's social blocking list preference if Fanboy's annoyance list is disabled.
197 fanboySocialBlockingListPreference.isEnabled = !fanboyAnnoyanceListEnabled
200 // Inflate a WebView to get the default user agent.
201 val inflater = requireActivity().layoutInflater
203 // `@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.
204 @SuppressLint("InflateParams") val bareWebViewLayout = inflater.inflate(R.layout.bare_webview, null, false)
206 // Get a handle for the bare WebView.
207 val bareWebView = bareWebViewLayout.findViewById<WebView>(R.id.bare_webview)
209 // Get the default user agent.
210 defaultUserAgent = bareWebView.settings.userAgentString
212 // Get the user agent arrays.
213 userAgentNamesArray = ArrayAdapter.createFromResource(requireContext(), R.array.user_agent_names, R.layout.spinner_item)
214 translatedUserAgentNamesArray = resources.getStringArray(R.array.translated_user_agent_names)
215 userAgentDataArray = resources.getStringArray(R.array.user_agent_data)
217 // Populate the user agent summary.
218 when (val userAgentArrayPosition = userAgentNamesArray.getPosition(userAgentName)) {
219 // The user agent name is not on the canonical list.
220 // 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.
221 UNRECOGNIZED_USER_AGENT -> userAgentPreference.summary = userAgentName
223 // Get the user agent text from the webview (which changes based on the version of Android and WebView installed).
224 SETTINGS_WEBVIEW_DEFAULT_USER_AGENT -> userAgentPreference.summary = "${translatedUserAgentNamesArray[userAgentArrayPosition]}:\n$defaultUserAgent"
226 // Display the custom user agent.
227 SETTINGS_CUSTOM_USER_AGENT -> userAgentPreference.setSummary(R.string.custom_user_agent)
229 // Get the user agent summary from the user agent data array.
230 else -> userAgentPreference.summary = "${translatedUserAgentNamesArray[userAgentArrayPosition]}:\n${userAgentDataArray[userAgentArrayPosition]}"
233 // Set the summary text for the custom user agent preference.
234 customUserAgentPreference.summary = sharedPreferences.getString(getString(R.string.custom_user_agent_key), getString(R.string.custom_user_agent_default_value))
236 // Only enable the custom user agent preference if the user agent is set to custom.
237 customUserAgentPreference.isEnabled = (userAgentPreference.summary == getString(R.string.custom_user_agent))
239 // Set the search URL as the summary text for the search preference when the preference screen is loaded.
240 if (searchString == getString(R.string.custom_url_item)) {
241 // Use R.string.custom_url, which will be translated, instead of the array value, which will not.
242 searchPreference.setSummary(R.string.custom_url)
244 // Set the array value as the summary text.
245 searchPreference.summary = searchString
248 // Set the summary text for the search custom URL (the default is `""`).
249 searchCustomURLPreference.summary = sharedPreferences.getString(getString(R.string.search_custom_url_key), getString(R.string.search_custom_url_default_value))
251 // Only enable the search custom URL preference if the search is set to a custom URL.
252 searchCustomURLPreference.isEnabled = (searchString == getString(R.string.custom_url_item))
254 // Set the summary text for the proxy preference.
255 proxyPreference.summary = when (proxyString) {
256 ProxyHelper.NONE -> getString(R.string.no_proxy_enabled)
257 ProxyHelper.TOR -> getString(R.string.tor_enabled)
258 ProxyHelper.I2P -> getString(R.string.i2p_enabled)
259 ProxyHelper.CUSTOM -> getString(R.string.custom_proxy)
260 else -> getString(R.string.no_proxy_enabled)
263 // Set the summary text for the custom proxy URL.
264 proxyCustomUrlPreference.summary = sharedPreferences.getString(getString(R.string.proxy_custom_url_key), getString(R.string.proxy_custom_url_default_value))
266 // Only enable the custom proxy URL if a custom proxy is selected.
267 proxyCustomUrlPreference.isEnabled = proxyString == ProxyHelper.CUSTOM
269 // Set the status of the clear and exit preferences.
270 clearCookiesPreference.isEnabled = !clearEverything
271 clearDomStoragePreference.isEnabled = !clearEverything
272 clearFormDataPreference.isEnabled = !clearEverything // Clear form data can be removed once the minimum API is >= 26.
273 clearLogcatPreference.isEnabled = !clearEverything
274 clearCachePreference.isEnabled = !clearEverything
276 // Set the homepage URL as the summary text for the homepage preference.
277 homepagePreference.summary = sharedPreferences.getString(getString(R.string.homepage_key), getString(R.string.homepage_default_value))
279 // Set the font size as the summary text for the preference.
280 fontSizePreference.summary = sharedPreferences.getString(getString(R.string.font_size_key), getString(R.string.font_size_default_value)) + "%"
282 // Get the app theme string arrays.
283 appThemeEntriesStringArray = resources.getStringArray(R.array.app_theme_entries)
284 appThemeEntryValuesStringArray = resources.getStringArray(R.array.app_theme_entry_values)
286 // Get the app theme entry number that matches the current app theme.
287 val appThemeEntryNumber: Int = when (sharedPreferences.getString(getString(R.string.app_theme_key), getString(R.string.app_theme_default_value))) {
288 appThemeEntryValuesStringArray[1] -> 1 // The light theme is selected.
289 appThemeEntryValuesStringArray[2] -> 2 // The dark theme is selected.
290 else -> 0 // The system default theme is selected.
293 // Set the current theme as the summary text for the preference.
294 appThemePreference.summary = appThemeEntriesStringArray[appThemeEntryNumber]
296 // Enable the WebView theme preference if the app theme is not set to light. Google does not allow light themes to display dark WebViews.
297 webViewThemePreference.isEnabled = (appThemeEntryNumber != 1)
299 // Get the WebView theme string arrays.
300 webViewThemeEntriesStringArray = resources.getStringArray(R.array.webview_theme_entries)
301 webViewThemeEntryValuesStringArray = resources.getStringArray(R.array.webview_theme_entry_values)
303 // Get the WebView theme entry number that matches the current WebView theme.
304 val webViewThemeEntryNumber: Int = when (sharedPreferences.getString(getString(R.string.webview_theme_key), getString(R.string.webview_theme_default_value))) {
305 webViewThemeEntryValuesStringArray[1] -> 1 // The light theme is selected.
306 webViewThemeEntryValuesStringArray[2] -> 2 // The dark theme is selected.
307 else -> 0 // The system default theme is selected.
310 // Set the current theme as the summary text for the preference.
311 webViewThemePreference.summary = webViewThemeEntriesStringArray[webViewThemeEntryNumber]
313 // Set the JavaScript icon.
314 if (javaScriptEnabled)
315 javaScriptPreference.setIcon(R.drawable.javascript_enabled)
317 javaScriptPreference.setIcon(R.drawable.privacy_mode)
319 // Set the cookies icon.
320 if (sharedPreferences.getBoolean(getString(R.string.cookies_key), false))
321 cookiesPreference.setIcon(R.drawable.cookies_enabled)
323 cookiesPreference.setIcon(R.drawable.cookies_disabled)
325 // Set the DOM storage icon.
326 if (javaScriptEnabled) { // JavaScript is enabled.
327 if (sharedPreferences.getBoolean(getString(R.string.dom_storage_key), false)) // DOM storage is enabled.
328 domStoragePreference.setIcon(R.drawable.dom_storage_enabled)
329 else // DOM storage is disabled.
330 domStoragePreference.setIcon(R.drawable.dom_storage_disabled)
331 } else { // JavaScript is disabled. DOM storage should be ghosted.
332 domStoragePreference.setIcon(R.drawable.dom_storage_ghosted)
335 // Set the save form data icon if API < 26. Save form data has no effect on API >= 26.
336 if (Build.VERSION.SDK_INT < 26) {
337 if (sharedPreferences.getBoolean(getString(R.string.save_form_data_key), false))
338 formDataPreference.setIcon(R.drawable.form_data_enabled)
340 formDataPreference.setIcon(R.drawable.form_data_disabled)
343 // Set the custom user agent icon.
344 if (customUserAgentPreference.isEnabled)
345 customUserAgentPreference.setIcon(R.drawable.custom_user_agent_enabled)
347 customUserAgentPreference.setIcon(R.drawable.custom_user_agent_ghosted)
349 // Set the incognito mode icon.
350 if (sharedPreferences.getBoolean(getString(R.string.incognito_mode_key), false))
351 incognitoModePreference.setIcon(R.drawable.incognito_mode_enabled)
353 incognitoModePreference.setIcon(R.drawable.incognito_mode_disabled)
355 // Set the allow screenshots icon.
356 if (sharedPreferences.getBoolean(getString(R.string.allow_screenshots_key), false))
357 allowScreenshotsPreference.setIcon(R.drawable.allow_screenshots_enabled)
359 allowScreenshotsPreference.setIcon(R.drawable.allow_screenshots_disabled)
361 // Set the EasyList icon.
362 if (sharedPreferences.getBoolean(getString(R.string.easylist_key), true))
363 easyListPreference.setIcon(R.drawable.block_ads_enabled)
365 easyListPreference.setIcon(R.drawable.block_ads_disabled)
367 // Set the EasyPrivacy icon.
368 if (sharedPreferences.getBoolean(getString(R.string.easyprivacy_key), true))
369 easyPrivacyPreference.setIcon(R.drawable.block_tracking_enabled)
371 easyPrivacyPreference.setIcon(R.drawable.block_tracking_disabled)
373 // Set the Fanboy lists icons.
374 if (fanboyAnnoyanceListEnabled) {
375 // Set the Fanboy annoyance list icon.
376 fanboyAnnoyanceListPreference.setIcon(R.drawable.social_media_enabled)
378 // Set the Fanboy social blocking list icon.
379 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_ghosted)
381 // Set the Fanboy annoyance list icon.
382 fanboyAnnoyanceListPreference.setIcon(R.drawable.social_media_disabled)
384 // Set the Fanboy social blocking list icon.
385 if (fanboySocialBlockingEnabled)
386 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_enabled)
388 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_disabled)
391 // Set the UltraList icon.
392 if (sharedPreferences.getBoolean(getString(R.string.ultralist_key), true))
393 ultraListPreference.setIcon(R.drawable.block_ads_enabled)
395 ultraListPreference.setIcon(R.drawable.block_ads_disabled)
397 // Set the UltraPrivacy icon.
398 if (sharedPreferences.getBoolean(getString(R.string.ultraprivacy_key), true))
399 ultraPrivacyPreference.setIcon(R.drawable.block_tracking_enabled)
401 ultraPrivacyPreference.setIcon(R.drawable.block_tracking_disabled)
403 // Set the block all third-party requests icon.
404 if (sharedPreferences.getBoolean(getString(R.string.block_all_third_party_requests), false))
405 blockAllThirdPartyRequestsPreference.setIcon(R.drawable.block_all_third_party_requests_enabled)
407 blockAllThirdPartyRequestsPreference.setIcon(R.drawable.block_all_third_party_requests_disabled)
409 // Set the Tracking Queries icon.
410 if (sharedPreferences.getBoolean(getString(R.string.tracking_queries_key), true))
411 trackingQueriesPreference.setIcon(R.drawable.modify_url_enabled)
413 trackingQueriesPreference.setIcon(R.drawable.modify_url_disabled)
415 // Set the AMP Redirects icon.
416 if (sharedPreferences.getBoolean(getString(R.string.amp_redirects_key), true))
417 ampRedirectsPreference.setIcon(R.drawable.modify_url_enabled)
419 ampRedirectsPreference.setIcon(R.drawable.modify_url_disabled)
421 // Set the search custom URL icon.
422 if (searchCustomURLPreference.isEnabled)
423 searchCustomURLPreference.setIcon(R.drawable.search_custom_enabled)
425 searchCustomURLPreference.setIcon(R.drawable.search_custom_ghosted)
427 // Set the proxy icons according to the theme and status.
428 if (proxyString == ProxyHelper.NONE) { // Proxying is disabled.
429 // Set the main proxy icon to be disabled.
430 proxyPreference.setIcon(R.drawable.proxy_disabled)
432 // Set the custom proxy URL icon to be ghosted.
433 proxyCustomUrlPreference.setIcon(R.drawable.proxy_ghosted)
434 } else { // Proxying is enabled.
435 // Set the main proxy icon to be enabled.
436 proxyPreference.setIcon(R.drawable.proxy_enabled)
438 // Set the custom proxy URL icon according to its status.
439 if (proxyCustomUrlPreference.isEnabled)
440 proxyCustomUrlPreference.setIcon(R.drawable.proxy_enabled)
442 proxyCustomUrlPreference.setIcon(R.drawable.proxy_ghosted)
445 // Set the full-screen browsing mode icons.
446 if (fullScreenBrowsingMode) { // Full-screen browsing mode is enabled.
447 // Set the full screen browsing mode preference icon.
448 fullScreenBrowsingModePreference.setIcon(R.drawable.full_screen_enabled)
450 // Set the hide app bar icon.
451 if (sharedPreferences.getBoolean(getString(R.string.hide_app_bar_key), true))
452 hideAppBarPreference.setIcon(R.drawable.app_bar_enabled)
454 hideAppBarPreference.setIcon(R.drawable.app_bar_disabled)
455 } else { // Full screen browsing mode is disabled.
457 fullScreenBrowsingModePreference.setIcon(R.drawable.full_screen_disabled)
458 hideAppBarPreference.setIcon(R.drawable.app_bar_ghosted)
461 // Set the display under cutouts icon.
462 if (sharedPreferences.getBoolean(getString(R.string.display_under_cutouts_key), false))
463 displayUnderCutoutsPreference.setIcon(R.drawable.display_under_cutouts_enabled)
465 displayUnderCutoutsPreference.setIcon(R.drawable.display_under_cutouts_disabled)
467 // Set the clear everything icon.
468 if (clearEverything) {
469 clearEverythingPreference.setIcon(R.drawable.clear_everything_enabled)
471 clearEverythingPreference.setIcon(R.drawable.clear_everything_disabled)
474 // Set the clear cookies icon.
475 if (clearEverything || sharedPreferences.getBoolean(getString(R.string.clear_cookies_key), true))
476 clearCookiesPreference.setIcon(R.drawable.clear_cookies_enabled)
478 clearCookiesPreference.setIcon(R.drawable.clear_cookies_disabled)
480 // Set the clear DOM storage icon.
481 if (clearEverything || sharedPreferences.getBoolean(getString(R.string.clear_dom_storage_key), true))
482 clearDomStoragePreference.setIcon(R.drawable.clear_dom_storage_enabled)
484 clearDomStoragePreference.setIcon(R.drawable.clear_dom_storage_disabled)
486 // Set the clear form data icon if the API < 26. It has no effect on newer versions of Android.
487 if (Build.VERSION.SDK_INT < 26) {
488 if (clearEverything || sharedPreferences.getBoolean(getString(R.string.clear_form_data_key), true))
489 clearFormDataPreference.setIcon(R.drawable.clear_form_data_enabled)
491 clearFormDataPreference.setIcon(R.drawable.clear_form_data_disabled)
494 // Set the clear logcat icon.
495 if (clearEverything || sharedPreferences.getBoolean(getString(R.string.clear_logcat_key), true))
496 clearLogcatPreference.setIcon(R.drawable.clear_logcat_enabled)
498 clearLogcatPreference.setIcon(R.drawable.clear_logcat_disabled)
500 // Set the clear cache icon.
501 if (clearEverything || sharedPreferences.getBoolean(getString(R.string.clear_cache_key), true))
502 clearCachePreference.setIcon(R.drawable.clear_cache_enabled)
504 clearCachePreference.setIcon(R.drawable.clear_cache_disabled)
506 // Set the open intents in new tab icon.
507 if (sharedPreferences.getBoolean(getString(R.string.open_intents_in_new_tab_key), true))
508 openIntentsInNewTabPreference.setIcon(R.drawable.tab_enabled)
510 openIntentsInNewTabPreference.setIcon(R.drawable.tab_disabled)
512 // Set the swipe to refresh icon.
513 if (sharedPreferences.getBoolean(getString(R.string.swipe_to_refresh_key), true))
514 swipeToRefreshPreference.setIcon(R.drawable.refresh_enabled)
516 swipeToRefreshPreference.setIcon(R.drawable.refresh_disabled)
518 // Set the download with external app icon.
519 if (sharedPreferences.getBoolean(getString(R.string.download_with_external_app_key), false))
520 downloadWithExternalAppPreference.setIcon(R.drawable.download_with_external_app_enabled)
522 downloadWithExternalAppPreference.setIcon(R.drawable.download_with_external_app_disabled)
524 // Set the scroll app bar icon.
525 if (sharedPreferences.getBoolean(getString(R.string.scroll_app_bar_key), true))
526 scrollAppBarPreference.setIcon(R.drawable.app_bar_enabled)
528 scrollAppBarPreference.setIcon(R.drawable.app_bar_disabled)
530 // Set the bottom app bar icon.
531 if (sharedPreferences.getBoolean(getString(R.string.bottom_app_bar_key), false))
532 bottomAppBarPreference.setIcon(R.drawable.bottom_app_bar_enabled)
534 bottomAppBarPreference.setIcon(R.drawable.bottom_app_bar_disabled)
536 // Set the display additional app bar icons icon.
537 if (sharedPreferences.getBoolean(getString(R.string.display_additional_app_bar_icons_key), false))
538 displayAdditionalAppBarIconsPreference.setIcon(R.drawable.more_enabled)
540 displayAdditionalAppBarIconsPreference.setIcon(R.drawable.more_disabled)
542 // Set the WebView theme icon.
543 if (webViewThemePreference.isEnabled) { // The WebView theme preference is enabled.
544 when (webViewThemeEntryNumber) {
545 // The system default WebView theme is selected.
547 // Get the current theme status.
548 val currentThemeStatus = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
550 // Set the icon according to the app theme.
551 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO)
552 webViewThemePreference.setIcon(R.drawable.webview_light_theme)
554 webViewThemePreference.setIcon(R.drawable.webview_dark_theme)
557 // The light WebView theme is selected.
560 webViewThemePreference.setIcon(R.drawable.webview_light_theme)
563 // The dark WebView theme is selected.
566 webViewThemePreference.setIcon(R.drawable.webview_dark_theme)
569 } else { // The WebView theme preference is disabled.
570 webViewThemePreference.setIcon(R.drawable.webview_theme_ghosted)
573 // Set the wide viewport icon.
574 if (sharedPreferences.getBoolean(getString(R.string.wide_viewport_key), true))
575 wideViewportPreference.setIcon(R.drawable.wide_viewport_enabled)
577 wideViewportPreference.setIcon(R.drawable.wide_viewport_disabled)
579 // Set the display webpage images icon.
580 if (sharedPreferences.getBoolean(getString(R.string.display_webpage_images_key), true))
581 displayWebpageImagesPreference.setIcon(R.drawable.images_enabled)
583 displayWebpageImagesPreference.setIcon(R.drawable.images_disabled)
586 // The listener should be unregistered when the app is paused.
587 override fun onPause() {
588 // Run the default commands.
591 // Get a handle for the shared preferences.
592 val sharedPreferences = preferenceScreen.sharedPreferences!!
594 // Unregister the shared preference listener.
595 sharedPreferences.unregisterOnSharedPreferenceChangeListener(sharedPreferenceChangeListener)
598 // The listener should be re-registered when the app is resumed.
599 override fun onResume() {
600 // Run the default commands.
603 // Get a new shared preference change listener.
604 sharedPreferenceChangeListener = getSharedPreferenceChangeListener()
606 // Get a handle for the shared preferences.
607 val sharedPreferences = preferenceScreen.sharedPreferences!!
609 // Re-register the shared preference listener.
610 sharedPreferences.registerOnSharedPreferenceChangeListener(sharedPreferenceChangeListener)
612 // Restore the scroll position if the fragment has been restarted.
613 if (fragmentRestarted) {
614 // Reset the fragment restarted flag.
615 fragmentRestarted = false
617 // Set the scroll position.
618 listView.post { listView.smoothScrollBy(0, scrollY) }
622 override fun onSaveInstanceState(savedInstanceState: Bundle) {
623 // Run the default commands.
624 super.onSaveInstanceState(savedInstanceState)
626 // Save the scroll position.
627 savedInstanceState.putInt(SCROLL_Y, listView.computeVerticalScrollOffset())
630 private fun getSharedPreferenceChangeListener(): OnSharedPreferenceChangeListener {
631 // Return the shared preference change listener.
632 return OnSharedPreferenceChangeListener { sharedPreferences: SharedPreferences, key: String? ->
634 getString(R.string.javascript_key) -> {
635 // Update the icons and the DOM storage preference status.
636 if (sharedPreferences.getBoolean(getString(R.string.javascript_key), false)) { // The JavaScript preference is enabled.
637 // Update the icon for the JavaScript preference.
638 javaScriptPreference.setIcon(R.drawable.javascript_enabled)
640 // Update the status of the DOM storage preference.
641 domStoragePreference.isEnabled = true
643 // Update the icon for the DOM storage preference.
644 if (sharedPreferences.getBoolean(getString(R.string.dom_storage_key), false))
645 domStoragePreference.setIcon(R.drawable.dom_storage_enabled)
647 domStoragePreference.setIcon(R.drawable.dom_storage_disabled)
648 } else { // The JavaScript preference is disabled.
649 // Update the icon for the JavaScript preference.
650 javaScriptPreference.setIcon(R.drawable.privacy_mode)
652 // Update the status of the DOM storage preference.
653 domStoragePreference.isEnabled = false
655 // Set the icon for DOM storage preference to be ghosted.
656 domStoragePreference.setIcon(R.drawable.dom_storage_ghosted)
660 getString(R.string.cookies_key) -> {
662 if (sharedPreferences.getBoolean(getString(R.string.cookies_key), false))
663 cookiesPreference.setIcon(R.drawable.cookies_enabled)
665 cookiesPreference.setIcon(R.drawable.cookies_disabled)
668 getString(R.string.dom_storage_key) -> {
670 if (sharedPreferences.getBoolean(getString(R.string.dom_storage_key), false))
671 domStoragePreference.setIcon(R.drawable.dom_storage_enabled)
673 domStoragePreference.setIcon(R.drawable.dom_storage_disabled)
676 getString(R.string.save_form_data_key) -> { // Saved form data can be removed once the minimum API >= 26.
678 if (sharedPreferences.getBoolean(getString(R.string.save_form_data_key), false))
679 formDataPreference.setIcon(R.drawable.form_data_enabled)
681 formDataPreference.setIcon(R.drawable.form_data_disabled)
684 getString(R.string.user_agent_key) -> {
685 // Get the new user agent name.
686 val newUserAgentName = sharedPreferences.getString(getString(R.string.user_agent_key), getString(R.string.user_agent_default_value))
688 // Get the array position for the new user agent name.
689 val newUserAgentArrayPosition = userAgentNamesArray.getPosition(newUserAgentName)
691 // Get the translated new user agent name.
692 val translatedNewUserAgentName = translatedUserAgentNamesArray[newUserAgentArrayPosition]
694 // Populate the user agent summary.
695 when (newUserAgentArrayPosition) {
696 SETTINGS_WEBVIEW_DEFAULT_USER_AGENT -> {
697 // Get the user agent text from the webview (which changes based on the version of Android and WebView installed).
698 userAgentPreference.summary = "$translatedNewUserAgentName:\n$defaultUserAgent"
700 // Disable the custom user agent preference.
701 customUserAgentPreference.isEnabled = false
703 // Set the custom user agent preference icon.
704 customUserAgentPreference.setIcon(R.drawable.custom_user_agent_ghosted)
707 SETTINGS_CUSTOM_USER_AGENT -> {
708 // Set the summary text.
709 userAgentPreference.setSummary(R.string.custom_user_agent)
711 // Enable the custom user agent preference.
712 customUserAgentPreference.isEnabled = true
714 // Set the custom user agent preference icon.
715 customUserAgentPreference.setIcon(R.drawable.custom_user_agent_enabled)
719 // Get the user agent summary from the user agent data array.
720 userAgentPreference.summary = "$translatedNewUserAgentName:\n${userAgentDataArray[newUserAgentArrayPosition]}"
722 // Disable the custom user agent preference.
723 customUserAgentPreference.isEnabled = false
725 // Set the custom user agent preference icon.
726 customUserAgentPreference.setIcon(R.drawable.custom_user_agent_ghosted)
731 getString(R.string.custom_user_agent_key) -> {
732 // Set the new custom user agent as the summary text for the preference.
733 customUserAgentPreference.summary = sharedPreferences.getString(getString(R.string.custom_user_agent_key), getString(R.string.custom_user_agent_default_value))
736 getString(R.string.incognito_mode_key) -> {
738 if (sharedPreferences.getBoolean(getString(R.string.incognito_mode_key), false))
739 incognitoModePreference.setIcon(R.drawable.incognito_mode_enabled)
741 incognitoModePreference.setIcon(R.drawable.incognito_mode_disabled)
744 getString(R.string.allow_screenshots_key) -> {
746 if (sharedPreferences.getBoolean(getString(R.string.allow_screenshots_key), false))
747 allowScreenshotsPreference.setIcon(R.drawable.allow_screenshots_enabled)
749 allowScreenshotsPreference.setIcon(R.drawable.allow_screenshots_disabled)
751 // Restart Privacy Browser.
752 restartPrivacyBrowser()
755 getString(R.string.easylist_key) -> {
757 if (sharedPreferences.getBoolean(getString(R.string.easylist_key), true))
758 easyListPreference.setIcon(R.drawable.block_ads_enabled)
760 easyListPreference.setIcon(R.drawable.block_ads_disabled)
763 getString(R.string.easyprivacy_key) -> {
765 if (sharedPreferences.getBoolean(getString(R.string.easyprivacy_key), true))
766 easyPrivacyPreference.setIcon(R.drawable.block_tracking_enabled)
768 easyPrivacyPreference.setIcon(R.drawable.block_tracking_disabled)
771 getString(R.string.fanboys_annoyance_list_key) -> {
772 // Get the current Fanboy settings.
773 val currentFanboyAnnoyanceList = sharedPreferences.getBoolean(getString(R.string.fanboys_annoyance_list_key), true)
774 val currentFanboySocialBlockingList = sharedPreferences.getBoolean(getString(R.string.fanboys_social_blocking_list_key), true)
776 // Update the Fanboy icons.
777 if (currentFanboyAnnoyanceList) { // Fanboy's annoyance list is enabled.
778 // Update the Fanboy's annoyance list icon.
779 fanboyAnnoyanceListPreference.setIcon(R.drawable.social_media_enabled)
781 // Update the Fanboy's social blocking list icon.
782 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_ghosted)
783 } else { // Fanboy's annoyance list is disabled.
784 // Update the Fanboy's annoyance list icon.
785 fanboyAnnoyanceListPreference.setIcon(R.drawable.social_media_disabled)
787 // Update the Fanboy's social blocking list icon.
788 if (currentFanboySocialBlockingList)
789 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_enabled)
791 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_disabled)
794 // Only enable Fanboy's social blocking list preference if Fanboy's annoyance list preference is disabled.
795 fanboySocialBlockingListPreference.isEnabled = !currentFanboyAnnoyanceList
798 getString(R.string.fanboys_social_blocking_list_key) -> {
800 if (sharedPreferences.getBoolean(getString(R.string.fanboys_social_blocking_list_key), true))
801 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_enabled)
803 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_disabled)
806 getString(R.string.ultralist_key) -> {
808 if (sharedPreferences.getBoolean(getString(R.string.ultralist_key), true))
809 ultraListPreference.setIcon(R.drawable.block_ads_enabled)
811 ultraListPreference.setIcon(R.drawable.block_ads_disabled)
814 getString(R.string.ultraprivacy_key) -> {
816 if (sharedPreferences.getBoolean(getString(R.string.ultraprivacy_key), true))
817 ultraPrivacyPreference.setIcon(R.drawable.block_tracking_enabled)
819 ultraPrivacyPreference.setIcon(R.drawable.block_tracking_disabled)
822 getString(R.string.block_all_third_party_requests_key) -> {
824 if (sharedPreferences.getBoolean(getString(R.string.block_all_third_party_requests_key), false)) {
825 blockAllThirdPartyRequestsPreference.setIcon(R.drawable.block_all_third_party_requests_enabled)
827 blockAllThirdPartyRequestsPreference.setIcon(R.drawable.block_all_third_party_requests_disabled)
831 getString(R.string.tracking_queries_key) -> {
833 if (sharedPreferences.getBoolean(getString(R.string.tracking_queries_key), true))
834 trackingQueriesPreference.setIcon(R.drawable.modify_url_enabled)
836 trackingQueriesPreference.setIcon(R.drawable.modify_url_disabled)
839 getString(R.string.amp_redirects_key) -> {
841 if (sharedPreferences.getBoolean(getString(R.string.amp_redirects_key), true))
842 ampRedirectsPreference.setIcon(R.drawable.modify_url_enabled)
844 ampRedirectsPreference.setIcon(R.drawable.modify_url_disabled)
847 getString(R.string.search_key) -> {
848 // Store the new search string.
849 val newSearchString = sharedPreferences.getString(getString(R.string.search_key), getString(R.string.search_default_value))
851 // Update the search and search custom URL preferences.
852 if (newSearchString == getString(R.string.custom_url_item)) { // A custom URL is selected.
853 // Set the summary text to `R.string.custom_url`, which is translated.
854 searchPreference.setSummary(R.string.custom_url)
856 // Enable the search custom URL preference.
857 searchCustomURLPreference.isEnabled = true
859 // Set the search custom URL preference icon.
860 searchCustomURLPreference.setIcon(R.drawable.search_custom_enabled)
861 } else { // A custom URL is not selected.
862 // Set the summary text to the new search string.
863 searchPreference.summary = newSearchString
865 // Disable the search custom URL Preference.
866 searchCustomURLPreference.isEnabled = false
868 // Set the search custom URL preference icon.
869 searchCustomURLPreference.setIcon(R.drawable.search_custom_ghosted)
873 getString(R.string.search_custom_url_key) -> {
874 // Set the new search custom URL as the summary text for the preference.
875 searchCustomURLPreference.summary = sharedPreferences.getString(getString(R.string.search_custom_url_key), getString(R.string.search_custom_url_default_value))
878 getString(R.string.proxy_key) -> {
879 // Get the current proxy string.
880 val currentProxyString = sharedPreferences.getString(getString(R.string.proxy_key), getString(R.string.proxy_default_value))
882 // Update the proxy preference summary text.
883 proxyPreference.summary = when (currentProxyString) {
884 ProxyHelper.NONE -> getString(R.string.no_proxy_enabled)
885 ProxyHelper.TOR -> getString(R.string.tor_enabled)
886 ProxyHelper.I2P -> getString(R.string.i2p_enabled)
887 ProxyHelper.CUSTOM -> getString(R.string.custom_proxy)
888 else -> getString(R.string.no_proxy_enabled)
891 // Update the status of the custom URL preference.
892 proxyCustomUrlPreference.isEnabled = currentProxyString == ProxyHelper.CUSTOM
895 if (currentProxyString == ProxyHelper.NONE) { // Proxying is disabled.
896 // Set the main proxy icon to be disabled
897 proxyPreference.setIcon(R.drawable.proxy_disabled)
899 // Set the custom proxy URL icon to be ghosted.
900 proxyCustomUrlPreference.setIcon(R.drawable.proxy_ghosted)
901 } else { // Proxying is enabled.
902 // Set the main proxy icon to be enabled.
903 proxyPreference.setIcon(R.drawable.proxy_enabled)
905 /// Set the custom proxy URL icon according to its status.
906 if (proxyCustomUrlPreference.isEnabled)
907 proxyCustomUrlPreference.setIcon(R.drawable.proxy_enabled)
909 proxyCustomUrlPreference.setIcon(R.drawable.proxy_ghosted)
913 getString(R.string.proxy_custom_url_key) -> {
914 // Set the summary text for the proxy custom URL.
915 proxyCustomUrlPreference.summary = sharedPreferences.getString(getString(R.string.proxy_custom_url_key), getString(R.string.proxy_custom_url_default_value))
918 getString(R.string.full_screen_browsing_mode_key) -> {
920 if (sharedPreferences.getBoolean(getString(R.string.full_screen_browsing_mode_key), false)) { // Full screen browsing is enabled.
921 // Set the full screen browsing mode preference icon.
922 fullScreenBrowsingModePreference.setIcon(R.drawable.full_screen_enabled)
924 // Set the hide app bar preference icon.
925 if (sharedPreferences.getBoolean(getString(R.string.hide_app_bar_key), true))
926 hideAppBarPreference.setIcon(R.drawable.app_bar_enabled)
928 hideAppBarPreference.setIcon(R.drawable.app_bar_disabled)
929 } else { // Full screen browsing is disabled.
931 fullScreenBrowsingModePreference.setIcon(R.drawable.full_screen_disabled)
932 hideAppBarPreference.setIcon(R.drawable.app_bar_ghosted)
936 getString(R.string.hide_app_bar_key) -> {
938 if (sharedPreferences.getBoolean(getString(R.string.hide_app_bar_key), true))
939 hideAppBarPreference.setIcon(R.drawable.app_bar_enabled)
941 hideAppBarPreference.setIcon(R.drawable.app_bar_disabled)
944 getString(R.string.display_under_cutouts_key) -> {
946 if (sharedPreferences.getBoolean(getString(R.string.display_under_cutouts_key), true))
947 displayUnderCutoutsPreference.setIcon(R.drawable.display_under_cutouts_enabled)
949 displayUnderCutoutsPreference.setIcon(R.drawable.display_under_cutouts_disabled)
951 // Restart Privacy Browser.
952 restartPrivacyBrowser()
955 getString(R.string.clear_everything_key) -> {
956 // Store the new clear everything status
957 val newClearEverythingBoolean = sharedPreferences.getBoolean(getString(R.string.clear_everything_key), true)
959 // Update the status of the clear and exit preferences.
960 clearCookiesPreference.isEnabled = !newClearEverythingBoolean
961 clearDomStoragePreference.isEnabled = !newClearEverythingBoolean
962 clearFormDataPreference.isEnabled = !newClearEverythingBoolean // Clear form data can be removed once the minimum API >= 26.
963 clearLogcatPreference.isEnabled = !newClearEverythingBoolean
964 clearCachePreference.isEnabled = !newClearEverythingBoolean
966 // Update the clear everything preference icon.
967 if (newClearEverythingBoolean)
968 clearEverythingPreference.setIcon(R.drawable.clear_everything_enabled)
970 clearEverythingPreference.setIcon(R.drawable.clear_everything_disabled)
972 // Update the clear cookies preference icon.
973 if (newClearEverythingBoolean || sharedPreferences.getBoolean(getString(R.string.clear_cookies_key), true))
974 clearCookiesPreference.setIcon(R.drawable.clear_cookies_enabled)
976 clearCookiesPreference.setIcon(R.drawable.clear_cookies_disabled)
978 // Update the clear dom storage preference icon.
979 if (newClearEverythingBoolean || sharedPreferences.getBoolean(getString(R.string.clear_dom_storage_key), true))
980 clearDomStoragePreference.setIcon(R.drawable.clear_dom_storage_enabled)
982 clearDomStoragePreference.setIcon(R.drawable.clear_dom_storage_disabled)
984 // Update the clear form data preference icon if the API < 26.
985 if (Build.VERSION.SDK_INT < 26) {
986 if (newClearEverythingBoolean || sharedPreferences.getBoolean(getString(R.string.clear_form_data_key), true))
987 clearFormDataPreference.setIcon(R.drawable.clear_form_data_enabled)
989 clearFormDataPreference.setIcon(R.drawable.clear_form_data_disabled)
992 // Update the clear logcat preference icon.
993 if (newClearEverythingBoolean || sharedPreferences.getBoolean(getString(R.string.clear_logcat_key), true))
994 clearLogcatPreference.setIcon(R.drawable.clear_logcat_enabled)
996 clearLogcatPreference.setIcon(R.drawable.clear_logcat_disabled)
998 // Update the clear cache preference icon.
999 if (newClearEverythingBoolean || sharedPreferences.getBoolean(getString(R.string.clear_cache_key), true))
1000 clearCachePreference.setIcon(R.drawable.clear_cache_enabled)
1002 clearCachePreference.setIcon(R.drawable.clear_cache_disabled)
1005 getString(R.string.clear_cookies_key) -> {
1007 if (sharedPreferences.getBoolean(getString(R.string.clear_cookies_key), true))
1008 clearCookiesPreference.setIcon(R.drawable.clear_cookies_enabled)
1010 clearCookiesPreference.setIcon(R.drawable.clear_cookies_disabled)
1013 getString(R.string.clear_dom_storage_key) -> {
1015 if (sharedPreferences.getBoolean(getString(R.string.clear_dom_storage_key), true))
1016 clearDomStoragePreference.setIcon(R.drawable.clear_dom_storage_enabled)
1018 clearDomStoragePreference.setIcon(R.drawable.clear_dom_storage_disabled)
1021 getString(R.string.clear_form_data_key) -> {
1023 if (sharedPreferences.getBoolean(getString(R.string.clear_form_data_key), true))
1024 clearFormDataPreference.setIcon(R.drawable.clear_form_data_enabled)
1026 clearFormDataPreference.setIcon(R.drawable.clear_form_data_disabled)
1029 getString(R.string.clear_logcat_key) -> {
1031 if (sharedPreferences.getBoolean(getString(R.string.clear_logcat_key), true))
1032 clearLogcatPreference.setIcon(R.drawable.clear_logcat_enabled)
1034 clearLogcatPreference.setIcon(R.drawable.clear_logcat_disabled)
1037 getString(R.string.clear_cache_key) -> {
1039 if (sharedPreferences.getBoolean(getString(R.string.clear_cache_key), true))
1040 clearCachePreference.setIcon(R.drawable.clear_cache_enabled)
1042 clearCachePreference.setIcon(R.drawable.clear_cache_disabled)
1045 getString(R.string.homepage_key) -> {
1046 // Set the new homepage URL as the summary text for the Homepage preference.
1047 homepagePreference.summary = sharedPreferences.getString(getString(R.string.homepage_key), getString(R.string.homepage_default_value))
1050 getString(R.string.font_size_key) -> {
1051 // Update the font size summary text.
1052 fontSizePreference.summary = sharedPreferences.getString(getString(R.string.font_size_key), getString(R.string.font_size_default_value)) + "%"
1055 getString(R.string.open_intents_in_new_tab_key) -> {
1057 if (sharedPreferences.getBoolean(getString(R.string.open_intents_in_new_tab_key), true))
1058 openIntentsInNewTabPreference.setIcon(R.drawable.tab_enabled)
1060 openIntentsInNewTabPreference.setIcon(R.drawable.tab_disabled)
1063 getString(R.string.swipe_to_refresh_key) -> {
1065 if (sharedPreferences.getBoolean(getString(R.string.swipe_to_refresh_key), true))
1066 swipeToRefreshPreference.setIcon(R.drawable.refresh_enabled)
1068 swipeToRefreshPreference.setIcon(R.drawable.refresh_disabled)
1071 getString(R.string.download_with_external_app_key) -> {
1073 if (sharedPreferences.getBoolean(getString(R.string.download_with_external_app_key), false))
1074 downloadWithExternalAppPreference.setIcon(R.drawable.download_with_external_app_enabled)
1076 downloadWithExternalAppPreference.setIcon(R.drawable.download_with_external_app_disabled)
1079 getString(R.string.scroll_app_bar_key) -> {
1081 if (sharedPreferences.getBoolean(getString(R.string.scroll_app_bar_key), true))
1082 scrollAppBarPreference.setIcon(R.drawable.app_bar_enabled)
1084 scrollAppBarPreference.setIcon(R.drawable.app_bar_disabled)
1087 getString(R.string.bottom_app_bar_key) -> {
1089 if (sharedPreferences.getBoolean(getString(R.string.bottom_app_bar_key), false))
1090 bottomAppBarPreference.setIcon(R.drawable.bottom_app_bar_enabled)
1092 bottomAppBarPreference.setIcon(R.drawable.bottom_app_bar_disabled)
1094 // Restart Privacy Browser.
1095 restartPrivacyBrowser()
1098 getString(R.string.display_additional_app_bar_icons_key) -> {
1100 if (sharedPreferences.getBoolean(getString(R.string.display_additional_app_bar_icons_key), false))
1101 displayAdditionalAppBarIconsPreference.setIcon(R.drawable.more_enabled)
1103 displayAdditionalAppBarIconsPreference.setIcon(R.drawable.more_disabled)
1105 // Restart Privacy Browser.
1106 restartPrivacyBrowser()
1109 getString(R.string.app_theme_key) -> {
1110 // Get the app theme entry number that matches the current app theme.
1111 val appThemeEntryNumber: Int = when (sharedPreferences.getString(getString(R.string.app_theme_key), getString(R.string.app_theme_default_value))) {
1112 appThemeEntryValuesStringArray[1] -> 1 // The light theme is selected.
1113 appThemeEntryValuesStringArray[2] -> 2 // The dark theme is selected.
1114 else -> 0 // The system default theme is selected.
1117 // Update the system according to the new theme.
1118 when (appThemeEntryNumber) {
1119 0 -> { // The system default theme is selected.
1120 // Update the theme preference summary text.
1121 appThemePreference.summary = appThemeEntriesStringArray[0]
1123 // Apply the new theme.
1124 if (Build.VERSION.SDK_INT >= 28) { // The system default theme is supported.
1125 // Follow the system default theme.
1126 AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
1127 } else { // The system default theme is not supported.
1128 // Follow the battery saver mode.
1129 AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_AUTO_BATTERY)
1133 1 -> { // The light theme is selected.
1134 // Update the theme preference summary text.
1135 appThemePreference.summary = appThemeEntriesStringArray[1]
1137 // Apply the new theme.
1138 AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
1141 2 -> { // The dark theme is selected.
1142 // Update the theme preference summary text.
1143 appThemePreference.summary = appThemeEntriesStringArray[2]
1145 // Apply the new theme.
1146 AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
1150 // Enable the WebView theme preference if the app theme is not set to light. Google does not allow light themes to display dark WebViews.
1151 webViewThemePreference.isEnabled = (appThemeEntryNumber != 1)
1153 // Get the webView theme entry number that matches the new WebView theme.
1154 val webViewThemeEntryNumber: Int = when (sharedPreferences.getString(getString(R.string.webview_theme_key), getString(R.string.webview_theme_default_value))) {
1155 webViewThemeEntriesStringArray[1] -> 1 // The light theme is selected.
1156 webViewThemeEntryValuesStringArray[2] -> 2 // The dark theme is selected.
1157 else -> 0 // The system default theme is selected.
1160 // Update the WebView theme icon.
1161 if (webViewThemePreference.isEnabled) { // The WebView theme preference is enabled.
1162 when (webViewThemeEntryNumber) {
1163 // The system default WebView theme is selected.
1165 // Get the current theme status.
1166 val currentThemeStatus = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
1168 // Set the icon according to the app theme.
1169 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO)
1170 webViewThemePreference.setIcon(R.drawable.webview_light_theme)
1172 webViewThemePreference.setIcon(R.drawable.webview_dark_theme)
1175 // The light WebView theme is selected.
1178 webViewThemePreference.setIcon(R.drawable.webview_light_theme)
1181 // The dark WebView theme is selected.
1184 webViewThemePreference.setIcon(R.drawable.webview_dark_theme)
1187 } else { // The WebView theme preference is disabled.
1188 webViewThemePreference.setIcon(R.drawable.webview_theme_ghosted)
1192 getString(R.string.webview_theme_key) -> {
1193 // Get the webView theme entry number that matches the new WebView theme.
1194 val newWebViewThemeEntryNumber: Int = when (sharedPreferences.getString(getString(R.string.webview_theme_key), getString(R.string.webview_theme_default_value))) {
1195 webViewThemeEntriesStringArray[1] -> 1 // The light theme is selected.
1196 webViewThemeEntryValuesStringArray[2] -> 2 // The dark theme is selected.
1197 else -> 0 // The system default theme is selected.
1200 // Update the WebView theme icon.
1201 when (newWebViewThemeEntryNumber) {
1202 // The system default WebView theme is selected.
1204 // Get the current theme status.
1205 val currentThemeStatus = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
1208 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO)
1209 webViewThemePreference.setIcon(R.drawable.webview_light_theme)
1211 webViewThemePreference.setIcon(R.drawable.webview_dark_theme)
1214 // The light WebView theme is selected.
1217 webViewThemePreference.setIcon(R.drawable.webview_light_theme)
1220 // The dark WebView theme is selected.
1223 webViewThemePreference.setIcon(R.drawable.webview_dark_theme)
1227 // Set the current theme as the summary text for the preference.
1228 webViewThemePreference.summary = webViewThemeEntriesStringArray[newWebViewThemeEntryNumber]
1231 getString(R.string.wide_viewport_key) -> {
1233 if (sharedPreferences.getBoolean(getString(R.string.wide_viewport_key), true))
1234 wideViewportPreference.setIcon(R.drawable.wide_viewport_enabled)
1236 wideViewportPreference.setIcon(R.drawable.wide_viewport_disabled)
1239 getString(R.string.display_webpage_images_key) -> {
1241 if (sharedPreferences.getBoolean(getString(R.string.display_webpage_images_key), true))
1242 displayWebpageImagesPreference.setIcon(R.drawable.images_enabled)
1244 displayWebpageImagesPreference.setIcon(R.drawable.images_disabled)
1250 private fun restartPrivacyBrowser() {
1251 // Create an intent to restart Privacy Browser.
1252 val restartIntent = requireActivity().parentActivityIntent!!
1254 // `Intent.FLAG_ACTIVITY_CLEAR_TASK` removes all activities from the stack. It requires `Intent.FLAG_ACTIVITY_NEW_TASK`.
1255 restartIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
1257 // Create a handler to restart the activity.
1258 val restartHandler = Handler(Looper.getMainLooper())
1260 // Create a runnable to restart the activity.
1261 val restartRunnable = Runnable {
1262 // Restart the activity.
1263 startActivity(restartIntent)
1265 // Kill this instance of Privacy Browser. Otherwise, the app exhibits sporadic behavior after the restart.
1269 // Restart the activity after 400 milliseconds, so that the app has enough time to save the change to the preference.
1270 restartHandler.postDelayed(restartRunnable, 400)