2 * Copyright 2016-2024 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 downloadProviderEntryValuesStringArray: Array<String>
77 private lateinit var downloadProviderPreference: Preference
78 private lateinit var easyListPreference: Preference
79 private lateinit var easyPrivacyPreference: Preference
80 private lateinit var fanboyAnnoyanceListPreference: Preference
81 private lateinit var fanboySocialBlockingListPreference: Preference
82 private lateinit var fontSizePreference: Preference
83 private lateinit var formDataPreference: Preference // The form data preference can be removed once the minimum API >= 26.
84 private lateinit var fullScreenBrowsingModePreference: Preference
85 private lateinit var hideAppBarPreference: Preference
86 private lateinit var displayUnderCutoutsPreference: Preference
87 private lateinit var homepagePreference: Preference
88 private lateinit var incognitoModePreference: Preference
89 private lateinit var javaScriptPreference: Preference
90 private lateinit var openIntentsInNewTabPreference: Preference
91 private lateinit var proxyCustomUrlPreference: Preference
92 private lateinit var proxyPreference: Preference
93 private lateinit var scrollAppBarPreference: Preference
94 private lateinit var searchCustomURLPreference: Preference
95 private lateinit var searchPreference: Preference
96 private lateinit var sharedPreferenceChangeListener: OnSharedPreferenceChangeListener
97 private lateinit var swipeToRefreshPreference: Preference
98 private lateinit var trackingQueriesPreference: Preference
99 private lateinit var translatedUserAgentNamesArray: Array<String>
100 private lateinit var ultraListPreference: Preference
101 private lateinit var ultraPrivacyPreference: Preference
102 private lateinit var userAgentDataArray: Array<String>
103 private lateinit var userAgentPreference: Preference
104 private lateinit var userAgentNamesArray: ArrayAdapter<CharSequence>
105 private lateinit var webViewThemeEntriesStringArray: Array<String>
106 private lateinit var webViewThemeEntryValuesStringArray: Array<String>
107 private lateinit var webViewThemePreference: Preference
108 private lateinit var wideViewportPreference: Preference
110 override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
111 // Check if the fragment has been restarted.
112 if (savedInstanceState != null) {
113 // Set the fragment restored flag.
114 fragmentRestarted = true
116 // Save the scroll Y.
117 scrollY = savedInstanceState.getInt(SCROLL_Y)
120 // Load the preferences from the XML file.
121 setPreferencesFromResource(R.xml.preferences, rootKey)
123 // Get a handle for the shared preferences.
124 val sharedPreferences = preferenceScreen.sharedPreferences!!
126 // Get handles for the preferences.
127 javaScriptPreference = findPreference(getString(R.string.javascript_key))!!
128 cookiesPreference = findPreference(getString(R.string.cookies_key))!!
129 domStoragePreference = findPreference(getString(R.string.dom_storage_key))!!
130 formDataPreference = findPreference(getString(R.string.save_form_data_key))!! // The form data preference can be removed once the minimum API >= 26.
131 userAgentPreference = findPreference(getString(R.string.user_agent_key))!!
132 customUserAgentPreference = findPreference(getString(R.string.custom_user_agent_key))!!
133 incognitoModePreference = findPreference(getString(R.string.incognito_mode_key))!!
134 allowScreenshotsPreference = findPreference(getString(R.string.allow_screenshots_key))!!
135 easyListPreference = findPreference(getString(R.string.easylist_key))!!
136 easyPrivacyPreference = findPreference(getString(R.string.easyprivacy_key))!!
137 fanboyAnnoyanceListPreference = findPreference(getString(R.string.fanboys_annoyance_list_key))!!
138 fanboySocialBlockingListPreference = findPreference(getString(R.string.fanboys_social_blocking_list_key))!!
139 ultraListPreference = findPreference(getString(R.string.ultralist_key))!!
140 ultraPrivacyPreference = findPreference(getString(R.string.ultraprivacy_key))!!
141 blockAllThirdPartyRequestsPreference = findPreference(getString(R.string.block_all_third_party_requests_key))!!
142 trackingQueriesPreference = findPreference(getString(R.string.tracking_queries_key))!!
143 ampRedirectsPreference = findPreference(getString(R.string.amp_redirects_key))!!
144 searchPreference = findPreference(getString(R.string.search_key))!!
145 searchCustomURLPreference = findPreference(getString(R.string.search_custom_url_key))!!
146 proxyPreference = findPreference(getString(R.string.proxy_key))!!
147 proxyCustomUrlPreference = findPreference(getString(R.string.proxy_custom_url_key))!!
148 fullScreenBrowsingModePreference = findPreference(getString(R.string.full_screen_browsing_mode_key))!!
149 hideAppBarPreference = findPreference(getString(R.string.hide_app_bar_key))!!
150 displayUnderCutoutsPreference = findPreference(getString(R.string.display_under_cutouts_key))!!
151 clearEverythingPreference = findPreference(getString(R.string.clear_everything_key))!!
152 clearCookiesPreference = findPreference(getString(R.string.clear_cookies_key))!!
153 clearDomStoragePreference = findPreference(getString(R.string.clear_dom_storage_key))!!
154 clearFormDataPreference = findPreference(getString(R.string.clear_form_data_key))!! // The clear form data preference can be removed once the minimum API >= 26.
155 clearLogcatPreference = findPreference(getString(R.string.clear_logcat_key))!!
156 clearCachePreference = findPreference(getString(R.string.clear_cache_key))!!
157 homepagePreference = findPreference(getString(R.string.homepage_key))!!
158 fontSizePreference = findPreference(getString(R.string.font_size_key))!!
159 openIntentsInNewTabPreference = findPreference(getString(R.string.open_intents_in_new_tab_key))!!
160 swipeToRefreshPreference = findPreference(getString(R.string.swipe_to_refresh_key))!!
161 downloadProviderPreference = findPreference(getString(R.string.download_provider_key))!!
162 scrollAppBarPreference = findPreference(getString(R.string.scroll_app_bar_key))!!
163 bottomAppBarPreference = findPreference(getString(R.string.bottom_app_bar_key))!!
164 displayAdditionalAppBarIconsPreference = findPreference(getString(R.string.display_additional_app_bar_icons_key))!!
165 appThemePreference = findPreference(getString(R.string.app_theme_key))!!
166 webViewThemePreference = findPreference(getString(R.string.webview_theme_key))!!
167 wideViewportPreference = findPreference(getString(R.string.wide_viewport_key))!!
168 displayWebpageImagesPreference = findPreference(getString(R.string.display_webpage_images_key))!!
170 // Set the preference dependencies.
171 domStoragePreference.dependency = getString(R.string.javascript_key)
172 hideAppBarPreference.dependency = getString(R.string.full_screen_browsing_mode_key)
173 displayUnderCutoutsPreference.dependency = getString(R.string.full_screen_browsing_mode_key)
175 // Get strings from the preferences.
176 val userAgentName = sharedPreferences.getString(getString(R.string.user_agent_key), getString(R.string.user_agent_default_value))
177 val searchString = sharedPreferences.getString(getString(R.string.search_key), getString(R.string.search_default_value))
178 val proxyString = sharedPreferences.getString(getString(R.string.proxy_key), getString(R.string.proxy_default_value))
180 // Get booleans that are used in multiple places from the preferences.
181 val javaScriptEnabled = sharedPreferences.getBoolean(getString(R.string.javascript_key), false)
182 val fanboyAnnoyanceListEnabled = sharedPreferences.getBoolean(getString(R.string.fanboys_annoyance_list_key), true)
183 val fanboySocialBlockingEnabled = sharedPreferences.getBoolean(getString(R.string.fanboys_social_blocking_list_key), true)
184 val fullScreenBrowsingMode = sharedPreferences.getBoolean(getString(R.string.full_screen_browsing_mode_key), false)
185 val clearEverything = sharedPreferences.getBoolean(getString(R.string.clear_everything_key), true)
187 // Remove the form data preferences if the API is >= 26 as they no longer do anything.
188 if (Build.VERSION.SDK_INT >= 26) {
189 // Get handles for the categories.
190 val privacyCategory = findPreference<PreferenceCategory>(getString(R.string.privacy_category_key))!!
191 val clearAndExitCategory = findPreference<PreferenceCategory>(getString(R.string.clear_and_exit_category_key))!!
193 // Remove the form data preferences.
194 privacyCategory.removePreference(formDataPreference)
195 clearAndExitCategory.removePreference(clearFormDataPreference)
198 // Only enable Fanboy's social blocking list preference if Fanboy's annoyance list is disabled.
199 fanboySocialBlockingListPreference.isEnabled = !fanboyAnnoyanceListEnabled
202 // Inflate a WebView to get the default user agent.
203 val inflater = requireActivity().layoutInflater
205 // `@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.
206 @SuppressLint("InflateParams") val bareWebViewLayout = inflater.inflate(R.layout.bare_webview, null, false)
208 // Get a handle for the bare WebView.
209 val bareWebView = bareWebViewLayout.findViewById<WebView>(R.id.bare_webview)
211 // Get the default user agent.
212 defaultUserAgent = bareWebView.settings.userAgentString
214 // Get the user agent arrays.
215 userAgentNamesArray = ArrayAdapter.createFromResource(requireContext(), R.array.user_agent_names, R.layout.spinner_item)
216 translatedUserAgentNamesArray = resources.getStringArray(R.array.translated_user_agent_names)
217 userAgentDataArray = resources.getStringArray(R.array.user_agent_data)
219 // Populate the user agent summary.
220 when (val userAgentArrayPosition = userAgentNamesArray.getPosition(userAgentName)) {
221 // The user agent name is not on the canonical list.
222 // 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.
223 UNRECOGNIZED_USER_AGENT -> userAgentPreference.summary = userAgentName
225 // Get the user agent text from the webview (which changes based on the version of Android and WebView installed).
226 SETTINGS_WEBVIEW_DEFAULT_USER_AGENT -> userAgentPreference.summary = "${translatedUserAgentNamesArray[userAgentArrayPosition]}:\n$defaultUserAgent"
228 // Display the custom user agent.
229 SETTINGS_CUSTOM_USER_AGENT -> userAgentPreference.setSummary(R.string.custom_user_agent)
231 // Get the user agent summary from the user agent data array.
232 else -> userAgentPreference.summary = "${translatedUserAgentNamesArray[userAgentArrayPosition]}:\n${userAgentDataArray[userAgentArrayPosition]}"
235 // Set the summary text for the custom user agent preference.
236 customUserAgentPreference.summary = sharedPreferences.getString(getString(R.string.custom_user_agent_key), getString(R.string.custom_user_agent_default_value))
238 // Only enable the custom user agent preference if the user agent is set to custom.
239 customUserAgentPreference.isEnabled = (userAgentPreference.summary == getString(R.string.custom_user_agent))
241 // Set the search URL as the summary text for the search preference when the preference screen is loaded.
242 if (searchString == getString(R.string.custom_url_item)) {
243 // Use R.string.custom_url, which will be translated, instead of the array value, which will not.
244 searchPreference.setSummary(R.string.custom_url)
246 // Set the array value as the summary text.
247 searchPreference.summary = searchString
250 // Set the summary text for the search custom URL (the default is `""`).
251 searchCustomURLPreference.summary = sharedPreferences.getString(getString(R.string.search_custom_url_key), getString(R.string.search_custom_url_default_value))
253 // Only enable the search custom URL preference if the search is set to a custom URL.
254 searchCustomURLPreference.isEnabled = (searchString == getString(R.string.custom_url_item))
256 // Set the summary text for the proxy preference.
257 proxyPreference.summary = when (proxyString) {
258 ProxyHelper.NONE -> getString(R.string.no_proxy_enabled)
259 ProxyHelper.TOR -> getString(R.string.tor_enabled)
260 ProxyHelper.I2P -> getString(R.string.i2p_enabled)
261 ProxyHelper.CUSTOM -> getString(R.string.custom_proxy)
262 else -> getString(R.string.no_proxy_enabled)
265 // Set the summary text for the custom proxy URL.
266 proxyCustomUrlPreference.summary = sharedPreferences.getString(getString(R.string.proxy_custom_url_key), getString(R.string.proxy_custom_url_default_value))
268 // Only enable the custom proxy URL if a custom proxy is selected.
269 proxyCustomUrlPreference.isEnabled = proxyString == ProxyHelper.CUSTOM
271 // Set the status of the clear and exit preferences.
272 clearCookiesPreference.isEnabled = !clearEverything
273 clearDomStoragePreference.isEnabled = !clearEverything
274 clearFormDataPreference.isEnabled = !clearEverything // Clear form data can be removed once the minimum API is >= 26.
275 clearLogcatPreference.isEnabled = !clearEverything
276 clearCachePreference.isEnabled = !clearEverything
278 // Set the homepage URL as the summary text for the homepage preference.
279 homepagePreference.summary = sharedPreferences.getString(getString(R.string.homepage_key), getString(R.string.homepage_default_value))
281 // Set the font size as the summary text for the preference.
282 fontSizePreference.summary = sharedPreferences.getString(getString(R.string.font_size_key), getString(R.string.font_size_default_value)) + "%"
284 // Get the download provider entry values string array
285 downloadProviderEntryValuesStringArray = resources.getStringArray(R.array.download_provider_entry_values)
287 // Set the summary text for the download provider preference.
288 downloadProviderPreference.summary = when (sharedPreferences.getString(getString(R.string.download_provider_key), getString(R.string.download_provider_default_value))) {
289 downloadProviderEntryValuesStringArray[0] -> getString(R.string.download_with_privacy_browser) // Privacy Browser is selected.
290 downloadProviderEntryValuesStringArray[1] -> getString(R.string.download_with_android_download_manager) // Android download manager is selected.
291 else -> getString(R.string.download_with_external_app) // External app is selected.
294 // Get the app theme string arrays.
295 appThemeEntriesStringArray = resources.getStringArray(R.array.app_theme_entries)
296 appThemeEntryValuesStringArray = resources.getStringArray(R.array.app_theme_entry_values)
298 // Get the app theme entry number that matches the current app theme.
299 val appThemeEntryNumber: Int = when (sharedPreferences.getString(getString(R.string.app_theme_key), getString(R.string.app_theme_default_value))) {
300 appThemeEntryValuesStringArray[1] -> 1 // The light theme is selected.
301 appThemeEntryValuesStringArray[2] -> 2 // The dark theme is selected.
302 else -> 0 // The system default theme is selected.
305 // Set the current theme as the summary text for the preference.
306 appThemePreference.summary = appThemeEntriesStringArray[appThemeEntryNumber]
308 // Enable the WebView theme preference if the app theme is not set to light. Google does not allow light themes to display dark WebViews.
309 webViewThemePreference.isEnabled = (appThemeEntryNumber != 1)
311 // Get the WebView theme string arrays.
312 webViewThemeEntriesStringArray = resources.getStringArray(R.array.webview_theme_entries)
313 webViewThemeEntryValuesStringArray = resources.getStringArray(R.array.webview_theme_entry_values)
315 // Get the WebView theme entry number that matches the current WebView theme.
316 val webViewThemeEntryNumber: Int = when (sharedPreferences.getString(getString(R.string.webview_theme_key), getString(R.string.webview_theme_default_value))) {
317 webViewThemeEntryValuesStringArray[1] -> 1 // The light theme is selected.
318 webViewThemeEntryValuesStringArray[2] -> 2 // The dark theme is selected.
319 else -> 0 // The system default theme is selected.
322 // Set the current theme as the summary text for the preference.
323 webViewThemePreference.summary = webViewThemeEntriesStringArray[webViewThemeEntryNumber]
325 // Set the JavaScript icon.
326 if (javaScriptEnabled)
327 javaScriptPreference.setIcon(R.drawable.javascript_enabled)
329 javaScriptPreference.setIcon(R.drawable.privacy_mode)
331 // Set the cookies icon.
332 if (sharedPreferences.getBoolean(getString(R.string.cookies_key), false))
333 cookiesPreference.setIcon(R.drawable.cookies_enabled)
335 cookiesPreference.setIcon(R.drawable.cookies_disabled)
337 // Set the DOM storage icon.
338 if (javaScriptEnabled) { // JavaScript is enabled.
339 if (sharedPreferences.getBoolean(getString(R.string.dom_storage_key), false)) // DOM storage is enabled.
340 domStoragePreference.setIcon(R.drawable.dom_storage_enabled)
341 else // DOM storage is disabled.
342 domStoragePreference.setIcon(R.drawable.dom_storage_disabled)
343 } else { // JavaScript is disabled. DOM storage should be ghosted.
344 domStoragePreference.setIcon(R.drawable.dom_storage_ghosted)
347 // Set the save form data icon if API < 26. Save form data has no effect on API >= 26.
348 if (Build.VERSION.SDK_INT < 26) {
349 if (sharedPreferences.getBoolean(getString(R.string.save_form_data_key), false))
350 formDataPreference.setIcon(R.drawable.form_data_enabled)
352 formDataPreference.setIcon(R.drawable.form_data_disabled)
355 // Set the custom user agent icon.
356 if (customUserAgentPreference.isEnabled)
357 customUserAgentPreference.setIcon(R.drawable.custom_user_agent_enabled)
359 customUserAgentPreference.setIcon(R.drawable.custom_user_agent_ghosted)
361 // Set the incognito mode icon.
362 if (sharedPreferences.getBoolean(getString(R.string.incognito_mode_key), false))
363 incognitoModePreference.setIcon(R.drawable.incognito_mode_enabled)
365 incognitoModePreference.setIcon(R.drawable.incognito_mode_disabled)
367 // Set the allow screenshots icon.
368 if (sharedPreferences.getBoolean(getString(R.string.allow_screenshots_key), false))
369 allowScreenshotsPreference.setIcon(R.drawable.allow_screenshots_enabled)
371 allowScreenshotsPreference.setIcon(R.drawable.allow_screenshots_disabled)
373 // Set the EasyList icon.
374 if (sharedPreferences.getBoolean(getString(R.string.easylist_key), true))
375 easyListPreference.setIcon(R.drawable.block_ads_enabled)
377 easyListPreference.setIcon(R.drawable.block_ads_disabled)
379 // Set the EasyPrivacy icon.
380 if (sharedPreferences.getBoolean(getString(R.string.easyprivacy_key), true))
381 easyPrivacyPreference.setIcon(R.drawable.block_tracking_enabled)
383 easyPrivacyPreference.setIcon(R.drawable.block_tracking_disabled)
385 // Set the Fanboy lists icons.
386 if (fanboyAnnoyanceListEnabled) {
387 // Set the Fanboy annoyance list icon.
388 fanboyAnnoyanceListPreference.setIcon(R.drawable.social_media_enabled)
390 // Set the Fanboy social blocking list icon.
391 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_ghosted)
393 // Set the Fanboy annoyance list icon.
394 fanboyAnnoyanceListPreference.setIcon(R.drawable.social_media_disabled)
396 // Set the Fanboy social blocking list icon.
397 if (fanboySocialBlockingEnabled)
398 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_enabled)
400 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_disabled)
403 // Set the UltraList icon.
404 if (sharedPreferences.getBoolean(getString(R.string.ultralist_key), true))
405 ultraListPreference.setIcon(R.drawable.block_ads_enabled)
407 ultraListPreference.setIcon(R.drawable.block_ads_disabled)
409 // Set the UltraPrivacy icon.
410 if (sharedPreferences.getBoolean(getString(R.string.ultraprivacy_key), true))
411 ultraPrivacyPreference.setIcon(R.drawable.block_tracking_enabled)
413 ultraPrivacyPreference.setIcon(R.drawable.block_tracking_disabled)
415 // Set the block all third-party requests icon.
416 if (sharedPreferences.getBoolean(getString(R.string.block_all_third_party_requests), false))
417 blockAllThirdPartyRequestsPreference.setIcon(R.drawable.block_all_third_party_requests_enabled)
419 blockAllThirdPartyRequestsPreference.setIcon(R.drawable.block_all_third_party_requests_disabled)
421 // Set the Tracking Queries icon.
422 if (sharedPreferences.getBoolean(getString(R.string.tracking_queries_key), true))
423 trackingQueriesPreference.setIcon(R.drawable.modify_url_enabled)
425 trackingQueriesPreference.setIcon(R.drawable.modify_url_disabled)
427 // Set the AMP Redirects icon.
428 if (sharedPreferences.getBoolean(getString(R.string.amp_redirects_key), true))
429 ampRedirectsPreference.setIcon(R.drawable.modify_url_enabled)
431 ampRedirectsPreference.setIcon(R.drawable.modify_url_disabled)
433 // Set the search custom URL icon.
434 if (searchCustomURLPreference.isEnabled)
435 searchCustomURLPreference.setIcon(R.drawable.search_custom_enabled)
437 searchCustomURLPreference.setIcon(R.drawable.search_custom_ghosted)
439 // Set the proxy icons according to the theme and status.
440 if (proxyString == ProxyHelper.NONE) { // Proxying is disabled.
441 // Set the main proxy icon to be disabled.
442 proxyPreference.setIcon(R.drawable.proxy_disabled)
444 // Set the custom proxy URL icon to be ghosted.
445 proxyCustomUrlPreference.setIcon(R.drawable.proxy_ghosted)
446 } else { // Proxying is enabled.
447 // Set the main proxy icon to be enabled.
448 proxyPreference.setIcon(R.drawable.proxy_enabled)
450 // Set the custom proxy URL icon according to its status.
451 if (proxyCustomUrlPreference.isEnabled)
452 proxyCustomUrlPreference.setIcon(R.drawable.proxy_enabled)
454 proxyCustomUrlPreference.setIcon(R.drawable.proxy_ghosted)
457 // Set the full-screen browsing mode icons.
458 if (fullScreenBrowsingMode) { // Full-screen browsing mode is enabled.
459 // Set the full screen browsing mode preference icon.
460 fullScreenBrowsingModePreference.setIcon(R.drawable.full_screen_enabled)
462 // Set the hide app bar icon.
463 if (sharedPreferences.getBoolean(getString(R.string.hide_app_bar_key), true))
464 hideAppBarPreference.setIcon(R.drawable.app_bar_enabled)
466 hideAppBarPreference.setIcon(R.drawable.app_bar_disabled)
467 } else { // Full screen browsing mode is disabled.
469 fullScreenBrowsingModePreference.setIcon(R.drawable.full_screen_disabled)
470 hideAppBarPreference.setIcon(R.drawable.app_bar_ghosted)
473 // Set the display under cutouts icon.
474 if (sharedPreferences.getBoolean(getString(R.string.display_under_cutouts_key), false))
475 displayUnderCutoutsPreference.setIcon(R.drawable.display_under_cutouts_enabled)
477 displayUnderCutoutsPreference.setIcon(R.drawable.display_under_cutouts_disabled)
479 // Set the clear everything icon.
480 if (clearEverything) {
481 clearEverythingPreference.setIcon(R.drawable.clear_everything_enabled)
483 clearEverythingPreference.setIcon(R.drawable.clear_everything_disabled)
486 // Set the clear cookies icon.
487 if (clearEverything || sharedPreferences.getBoolean(getString(R.string.clear_cookies_key), true))
488 clearCookiesPreference.setIcon(R.drawable.clear_cookies_enabled)
490 clearCookiesPreference.setIcon(R.drawable.clear_cookies_disabled)
492 // Set the clear DOM storage icon.
493 if (clearEverything || sharedPreferences.getBoolean(getString(R.string.clear_dom_storage_key), true))
494 clearDomStoragePreference.setIcon(R.drawable.clear_dom_storage_enabled)
496 clearDomStoragePreference.setIcon(R.drawable.clear_dom_storage_disabled)
498 // Set the clear form data icon if the API < 26. It has no effect on newer versions of Android.
499 if (Build.VERSION.SDK_INT < 26) {
500 if (clearEverything || sharedPreferences.getBoolean(getString(R.string.clear_form_data_key), true))
501 clearFormDataPreference.setIcon(R.drawable.clear_form_data_enabled)
503 clearFormDataPreference.setIcon(R.drawable.clear_form_data_disabled)
506 // Set the clear logcat icon.
507 if (clearEverything || sharedPreferences.getBoolean(getString(R.string.clear_logcat_key), true))
508 clearLogcatPreference.setIcon(R.drawable.clear_logcat_enabled)
510 clearLogcatPreference.setIcon(R.drawable.clear_logcat_disabled)
512 // Set the clear cache icon.
513 if (clearEverything || sharedPreferences.getBoolean(getString(R.string.clear_cache_key), true))
514 clearCachePreference.setIcon(R.drawable.clear_cache_enabled)
516 clearCachePreference.setIcon(R.drawable.clear_cache_disabled)
518 // Set the open intents in new tab icon.
519 if (sharedPreferences.getBoolean(getString(R.string.open_intents_in_new_tab_key), true))
520 openIntentsInNewTabPreference.setIcon(R.drawable.tab_enabled)
522 openIntentsInNewTabPreference.setIcon(R.drawable.tab_disabled)
524 // Set the swipe to refresh icon.
525 if (sharedPreferences.getBoolean(getString(R.string.swipe_to_refresh_key), true))
526 swipeToRefreshPreference.setIcon(R.drawable.refresh_enabled)
528 swipeToRefreshPreference.setIcon(R.drawable.refresh_disabled)
530 // Set the scroll app bar icon.
531 if (sharedPreferences.getBoolean(getString(R.string.scroll_app_bar_key), false))
532 scrollAppBarPreference.setIcon(R.drawable.app_bar_enabled)
534 scrollAppBarPreference.setIcon(R.drawable.app_bar_disabled)
536 // Set the bottom app bar icon.
537 if (sharedPreferences.getBoolean(getString(R.string.bottom_app_bar_key), false))
538 bottomAppBarPreference.setIcon(R.drawable.bottom_app_bar_enabled)
540 bottomAppBarPreference.setIcon(R.drawable.bottom_app_bar_disabled)
542 // Set the display additional app bar icons icon.
543 if (sharedPreferences.getBoolean(getString(R.string.display_additional_app_bar_icons_key), false))
544 displayAdditionalAppBarIconsPreference.setIcon(R.drawable.more_enabled)
546 displayAdditionalAppBarIconsPreference.setIcon(R.drawable.more_disabled)
548 // Set the WebView theme icon.
549 if (webViewThemePreference.isEnabled) { // The WebView theme preference is enabled.
550 when (webViewThemeEntryNumber) {
551 // The system default WebView theme is selected.
553 // Get the current theme status.
554 val currentThemeStatus = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
556 // Set the icon according to the app theme.
557 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO)
558 webViewThemePreference.setIcon(R.drawable.webview_light_theme)
560 webViewThemePreference.setIcon(R.drawable.webview_dark_theme)
563 // The light WebView theme is selected.
566 webViewThemePreference.setIcon(R.drawable.webview_light_theme)
569 // The dark WebView theme is selected.
572 webViewThemePreference.setIcon(R.drawable.webview_dark_theme)
575 } else { // The WebView theme preference is disabled.
576 webViewThemePreference.setIcon(R.drawable.webview_theme_ghosted)
579 // Set the wide viewport icon.
580 if (sharedPreferences.getBoolean(getString(R.string.wide_viewport_key), true))
581 wideViewportPreference.setIcon(R.drawable.wide_viewport_enabled)
583 wideViewportPreference.setIcon(R.drawable.wide_viewport_disabled)
585 // Set the display webpage images icon.
586 if (sharedPreferences.getBoolean(getString(R.string.display_webpage_images_key), true))
587 displayWebpageImagesPreference.setIcon(R.drawable.images_enabled)
589 displayWebpageImagesPreference.setIcon(R.drawable.images_disabled)
592 // The listener should be unregistered when the app is paused.
593 override fun onPause() {
594 // Run the default commands.
597 // Get a handle for the shared preferences.
598 val sharedPreferences = preferenceScreen.sharedPreferences!!
600 // Unregister the shared preference listener.
601 sharedPreferences.unregisterOnSharedPreferenceChangeListener(sharedPreferenceChangeListener)
604 // The listener should be re-registered when the app is resumed.
605 override fun onResume() {
606 // Run the default commands.
609 // Get a new shared preference change listener.
610 sharedPreferenceChangeListener = getSharedPreferenceChangeListener()
612 // Get a handle for the shared preferences.
613 val sharedPreferences = preferenceScreen.sharedPreferences!!
615 // Re-register the shared preference listener.
616 sharedPreferences.registerOnSharedPreferenceChangeListener(sharedPreferenceChangeListener)
618 // Restore the scroll position if the fragment has been restarted.
619 if (fragmentRestarted) {
620 // Reset the fragment restarted flag.
621 fragmentRestarted = false
623 // Set the scroll position.
624 listView.post { listView.smoothScrollBy(0, scrollY) }
628 override fun onSaveInstanceState(savedInstanceState: Bundle) {
629 // Run the default commands.
630 super.onSaveInstanceState(savedInstanceState)
632 // Save the scroll position.
633 savedInstanceState.putInt(SCROLL_Y, listView.computeVerticalScrollOffset())
636 private fun getSharedPreferenceChangeListener(): OnSharedPreferenceChangeListener {
637 // Return the shared preference change listener.
638 return OnSharedPreferenceChangeListener { sharedPreferences: SharedPreferences, key: String? ->
640 getString(R.string.javascript_key) -> {
641 // Update the icons and the DOM storage preference status.
642 if (sharedPreferences.getBoolean(getString(R.string.javascript_key), false)) { // The JavaScript preference is enabled.
643 // Update the icon for the JavaScript preference.
644 javaScriptPreference.setIcon(R.drawable.javascript_enabled)
646 // Update the status of the DOM storage preference.
647 domStoragePreference.isEnabled = true
649 // Update the icon for the DOM storage preference.
650 if (sharedPreferences.getBoolean(getString(R.string.dom_storage_key), false))
651 domStoragePreference.setIcon(R.drawable.dom_storage_enabled)
653 domStoragePreference.setIcon(R.drawable.dom_storage_disabled)
654 } else { // The JavaScript preference is disabled.
655 // Update the icon for the JavaScript preference.
656 javaScriptPreference.setIcon(R.drawable.privacy_mode)
658 // Update the status of the DOM storage preference.
659 domStoragePreference.isEnabled = false
661 // Set the icon for DOM storage preference to be ghosted.
662 domStoragePreference.setIcon(R.drawable.dom_storage_ghosted)
666 getString(R.string.cookies_key) -> {
668 if (sharedPreferences.getBoolean(getString(R.string.cookies_key), false))
669 cookiesPreference.setIcon(R.drawable.cookies_enabled)
671 cookiesPreference.setIcon(R.drawable.cookies_disabled)
674 getString(R.string.dom_storage_key) -> {
676 if (sharedPreferences.getBoolean(getString(R.string.dom_storage_key), false))
677 domStoragePreference.setIcon(R.drawable.dom_storage_enabled)
679 domStoragePreference.setIcon(R.drawable.dom_storage_disabled)
682 getString(R.string.save_form_data_key) -> { // Saved form data can be removed once the minimum API >= 26.
684 if (sharedPreferences.getBoolean(getString(R.string.save_form_data_key), false))
685 formDataPreference.setIcon(R.drawable.form_data_enabled)
687 formDataPreference.setIcon(R.drawable.form_data_disabled)
690 getString(R.string.user_agent_key) -> {
691 // Get the new user agent name.
692 val newUserAgentName = sharedPreferences.getString(getString(R.string.user_agent_key), getString(R.string.user_agent_default_value))
694 // Get the array position for the new user agent name.
695 val newUserAgentArrayPosition = userAgentNamesArray.getPosition(newUserAgentName)
697 // Get the translated new user agent name.
698 val translatedNewUserAgentName = translatedUserAgentNamesArray[newUserAgentArrayPosition]
700 // Populate the user agent summary.
701 when (newUserAgentArrayPosition) {
702 SETTINGS_WEBVIEW_DEFAULT_USER_AGENT -> {
703 // Get the user agent text from the webview (which changes based on the version of Android and WebView installed).
704 userAgentPreference.summary = "$translatedNewUserAgentName:\n$defaultUserAgent"
706 // Disable the custom user agent preference.
707 customUserAgentPreference.isEnabled = false
709 // Set the custom user agent preference icon.
710 customUserAgentPreference.setIcon(R.drawable.custom_user_agent_ghosted)
713 SETTINGS_CUSTOM_USER_AGENT -> {
714 // Set the summary text.
715 userAgentPreference.setSummary(R.string.custom_user_agent)
717 // Enable the custom user agent preference.
718 customUserAgentPreference.isEnabled = true
720 // Set the custom user agent preference icon.
721 customUserAgentPreference.setIcon(R.drawable.custom_user_agent_enabled)
725 // Get the user agent summary from the user agent data array.
726 userAgentPreference.summary = "$translatedNewUserAgentName:\n${userAgentDataArray[newUserAgentArrayPosition]}"
728 // Disable the custom user agent preference.
729 customUserAgentPreference.isEnabled = false
731 // Set the custom user agent preference icon.
732 customUserAgentPreference.setIcon(R.drawable.custom_user_agent_ghosted)
737 getString(R.string.custom_user_agent_key) -> {
738 // Set the new custom user agent as the summary text for the preference.
739 customUserAgentPreference.summary = sharedPreferences.getString(getString(R.string.custom_user_agent_key), getString(R.string.custom_user_agent_default_value))
742 getString(R.string.incognito_mode_key) -> {
744 if (sharedPreferences.getBoolean(getString(R.string.incognito_mode_key), false))
745 incognitoModePreference.setIcon(R.drawable.incognito_mode_enabled)
747 incognitoModePreference.setIcon(R.drawable.incognito_mode_disabled)
750 getString(R.string.allow_screenshots_key) -> {
752 if (sharedPreferences.getBoolean(getString(R.string.allow_screenshots_key), false))
753 allowScreenshotsPreference.setIcon(R.drawable.allow_screenshots_enabled)
755 allowScreenshotsPreference.setIcon(R.drawable.allow_screenshots_disabled)
757 // Restart Privacy Browser.
758 restartPrivacyBrowser()
761 getString(R.string.easylist_key) -> {
763 if (sharedPreferences.getBoolean(getString(R.string.easylist_key), true))
764 easyListPreference.setIcon(R.drawable.block_ads_enabled)
766 easyListPreference.setIcon(R.drawable.block_ads_disabled)
769 getString(R.string.easyprivacy_key) -> {
771 if (sharedPreferences.getBoolean(getString(R.string.easyprivacy_key), true))
772 easyPrivacyPreference.setIcon(R.drawable.block_tracking_enabled)
774 easyPrivacyPreference.setIcon(R.drawable.block_tracking_disabled)
777 getString(R.string.fanboys_annoyance_list_key) -> {
778 // Get the current Fanboy settings.
779 val currentFanboyAnnoyanceList = sharedPreferences.getBoolean(getString(R.string.fanboys_annoyance_list_key), true)
780 val currentFanboySocialBlockingList = sharedPreferences.getBoolean(getString(R.string.fanboys_social_blocking_list_key), true)
782 // Update the Fanboy icons.
783 if (currentFanboyAnnoyanceList) { // Fanboy's annoyance list is enabled.
784 // Update the Fanboy's annoyance list icon.
785 fanboyAnnoyanceListPreference.setIcon(R.drawable.social_media_enabled)
787 // Update the Fanboy's social blocking list icon.
788 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_ghosted)
789 } else { // Fanboy's annoyance list is disabled.
790 // Update the Fanboy's annoyance list icon.
791 fanboyAnnoyanceListPreference.setIcon(R.drawable.social_media_disabled)
793 // Update the Fanboy's social blocking list icon.
794 if (currentFanboySocialBlockingList)
795 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_enabled)
797 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_disabled)
800 // Only enable Fanboy's social blocking list preference if Fanboy's annoyance list preference is disabled.
801 fanboySocialBlockingListPreference.isEnabled = !currentFanboyAnnoyanceList
804 getString(R.string.fanboys_social_blocking_list_key) -> {
806 if (sharedPreferences.getBoolean(getString(R.string.fanboys_social_blocking_list_key), true))
807 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_enabled)
809 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_disabled)
812 getString(R.string.ultralist_key) -> {
814 if (sharedPreferences.getBoolean(getString(R.string.ultralist_key), true))
815 ultraListPreference.setIcon(R.drawable.block_ads_enabled)
817 ultraListPreference.setIcon(R.drawable.block_ads_disabled)
820 getString(R.string.ultraprivacy_key) -> {
822 if (sharedPreferences.getBoolean(getString(R.string.ultraprivacy_key), true))
823 ultraPrivacyPreference.setIcon(R.drawable.block_tracking_enabled)
825 ultraPrivacyPreference.setIcon(R.drawable.block_tracking_disabled)
828 getString(R.string.block_all_third_party_requests_key) -> {
830 if (sharedPreferences.getBoolean(getString(R.string.block_all_third_party_requests_key), false)) {
831 blockAllThirdPartyRequestsPreference.setIcon(R.drawable.block_all_third_party_requests_enabled)
833 blockAllThirdPartyRequestsPreference.setIcon(R.drawable.block_all_third_party_requests_disabled)
837 getString(R.string.tracking_queries_key) -> {
839 if (sharedPreferences.getBoolean(getString(R.string.tracking_queries_key), true))
840 trackingQueriesPreference.setIcon(R.drawable.modify_url_enabled)
842 trackingQueriesPreference.setIcon(R.drawable.modify_url_disabled)
845 getString(R.string.amp_redirects_key) -> {
847 if (sharedPreferences.getBoolean(getString(R.string.amp_redirects_key), true))
848 ampRedirectsPreference.setIcon(R.drawable.modify_url_enabled)
850 ampRedirectsPreference.setIcon(R.drawable.modify_url_disabled)
853 getString(R.string.search_key) -> {
854 // Store the new search string.
855 val newSearchString = sharedPreferences.getString(getString(R.string.search_key), getString(R.string.search_default_value))
857 // Update the search and search custom URL preferences.
858 if (newSearchString == getString(R.string.custom_url_item)) { // A custom URL is selected.
859 // Set the summary text to `R.string.custom_url`, which is translated.
860 searchPreference.setSummary(R.string.custom_url)
862 // Enable the search custom URL preference.
863 searchCustomURLPreference.isEnabled = true
865 // Set the search custom URL preference icon.
866 searchCustomURLPreference.setIcon(R.drawable.search_custom_enabled)
867 } else { // A custom URL is not selected.
868 // Set the summary text to the new search string.
869 searchPreference.summary = newSearchString
871 // Disable the search custom URL Preference.
872 searchCustomURLPreference.isEnabled = false
874 // Set the search custom URL preference icon.
875 searchCustomURLPreference.setIcon(R.drawable.search_custom_ghosted)
879 getString(R.string.search_custom_url_key) -> {
880 // Set the new search custom URL as the summary text for the preference.
881 searchCustomURLPreference.summary = sharedPreferences.getString(getString(R.string.search_custom_url_key), getString(R.string.search_custom_url_default_value))
884 getString(R.string.proxy_key) -> {
885 // Get the current proxy string.
886 val currentProxyString = sharedPreferences.getString(getString(R.string.proxy_key), getString(R.string.proxy_default_value))
888 // Update the proxy preference summary text.
889 proxyPreference.summary = when (currentProxyString) {
890 ProxyHelper.NONE -> getString(R.string.no_proxy_enabled)
891 ProxyHelper.TOR -> getString(R.string.tor_enabled)
892 ProxyHelper.I2P -> getString(R.string.i2p_enabled)
893 ProxyHelper.CUSTOM -> getString(R.string.custom_proxy)
894 else -> getString(R.string.no_proxy_enabled)
897 // Update the status of the custom URL preference.
898 proxyCustomUrlPreference.isEnabled = currentProxyString == ProxyHelper.CUSTOM
901 if (currentProxyString == ProxyHelper.NONE) { // Proxying is disabled.
902 // Set the main proxy icon to be disabled
903 proxyPreference.setIcon(R.drawable.proxy_disabled)
905 // Set the custom proxy URL icon to be ghosted.
906 proxyCustomUrlPreference.setIcon(R.drawable.proxy_ghosted)
907 } else { // Proxying is enabled.
908 // Set the main proxy icon to be enabled.
909 proxyPreference.setIcon(R.drawable.proxy_enabled)
911 /// Set the custom proxy URL icon according to its status.
912 if (proxyCustomUrlPreference.isEnabled)
913 proxyCustomUrlPreference.setIcon(R.drawable.proxy_enabled)
915 proxyCustomUrlPreference.setIcon(R.drawable.proxy_ghosted)
919 getString(R.string.proxy_custom_url_key) -> {
920 // Set the summary text for the proxy custom URL.
921 proxyCustomUrlPreference.summary = sharedPreferences.getString(getString(R.string.proxy_custom_url_key), getString(R.string.proxy_custom_url_default_value))
924 getString(R.string.full_screen_browsing_mode_key) -> {
926 if (sharedPreferences.getBoolean(getString(R.string.full_screen_browsing_mode_key), false)) { // Full screen browsing is enabled.
927 // Set the full screen browsing mode preference icon.
928 fullScreenBrowsingModePreference.setIcon(R.drawable.full_screen_enabled)
930 // Set the hide app bar preference icon.
931 if (sharedPreferences.getBoolean(getString(R.string.hide_app_bar_key), true))
932 hideAppBarPreference.setIcon(R.drawable.app_bar_enabled)
934 hideAppBarPreference.setIcon(R.drawable.app_bar_disabled)
935 } else { // Full screen browsing is disabled.
937 fullScreenBrowsingModePreference.setIcon(R.drawable.full_screen_disabled)
938 hideAppBarPreference.setIcon(R.drawable.app_bar_ghosted)
942 getString(R.string.hide_app_bar_key) -> {
944 if (sharedPreferences.getBoolean(getString(R.string.hide_app_bar_key), true))
945 hideAppBarPreference.setIcon(R.drawable.app_bar_enabled)
947 hideAppBarPreference.setIcon(R.drawable.app_bar_disabled)
950 getString(R.string.display_under_cutouts_key) -> {
952 if (sharedPreferences.getBoolean(getString(R.string.display_under_cutouts_key), true))
953 displayUnderCutoutsPreference.setIcon(R.drawable.display_under_cutouts_enabled)
955 displayUnderCutoutsPreference.setIcon(R.drawable.display_under_cutouts_disabled)
957 // Restart Privacy Browser.
958 restartPrivacyBrowser()
961 getString(R.string.clear_everything_key) -> {
962 // Store the new clear everything status
963 val newClearEverythingBoolean = sharedPreferences.getBoolean(getString(R.string.clear_everything_key), true)
965 // Update the status of the clear and exit preferences.
966 clearCookiesPreference.isEnabled = !newClearEverythingBoolean
967 clearDomStoragePreference.isEnabled = !newClearEverythingBoolean
968 clearFormDataPreference.isEnabled = !newClearEverythingBoolean // Clear form data can be removed once the minimum API >= 26.
969 clearLogcatPreference.isEnabled = !newClearEverythingBoolean
970 clearCachePreference.isEnabled = !newClearEverythingBoolean
972 // Update the clear everything preference icon.
973 if (newClearEverythingBoolean)
974 clearEverythingPreference.setIcon(R.drawable.clear_everything_enabled)
976 clearEverythingPreference.setIcon(R.drawable.clear_everything_disabled)
978 // Update the clear cookies preference icon.
979 if (newClearEverythingBoolean || sharedPreferences.getBoolean(getString(R.string.clear_cookies_key), true))
980 clearCookiesPreference.setIcon(R.drawable.clear_cookies_enabled)
982 clearCookiesPreference.setIcon(R.drawable.clear_cookies_disabled)
984 // Update the clear dom storage preference icon.
985 if (newClearEverythingBoolean || sharedPreferences.getBoolean(getString(R.string.clear_dom_storage_key), true))
986 clearDomStoragePreference.setIcon(R.drawable.clear_dom_storage_enabled)
988 clearDomStoragePreference.setIcon(R.drawable.clear_dom_storage_disabled)
990 // Update the clear form data preference icon if the API < 26.
991 if (Build.VERSION.SDK_INT < 26) {
992 if (newClearEverythingBoolean || sharedPreferences.getBoolean(getString(R.string.clear_form_data_key), true))
993 clearFormDataPreference.setIcon(R.drawable.clear_form_data_enabled)
995 clearFormDataPreference.setIcon(R.drawable.clear_form_data_disabled)
998 // Update the clear logcat preference icon.
999 if (newClearEverythingBoolean || sharedPreferences.getBoolean(getString(R.string.clear_logcat_key), true))
1000 clearLogcatPreference.setIcon(R.drawable.clear_logcat_enabled)
1002 clearLogcatPreference.setIcon(R.drawable.clear_logcat_disabled)
1004 // Update the clear cache preference icon.
1005 if (newClearEverythingBoolean || sharedPreferences.getBoolean(getString(R.string.clear_cache_key), true))
1006 clearCachePreference.setIcon(R.drawable.clear_cache_enabled)
1008 clearCachePreference.setIcon(R.drawable.clear_cache_disabled)
1011 getString(R.string.clear_cookies_key) -> {
1013 if (sharedPreferences.getBoolean(getString(R.string.clear_cookies_key), true))
1014 clearCookiesPreference.setIcon(R.drawable.clear_cookies_enabled)
1016 clearCookiesPreference.setIcon(R.drawable.clear_cookies_disabled)
1019 getString(R.string.clear_dom_storage_key) -> {
1021 if (sharedPreferences.getBoolean(getString(R.string.clear_dom_storage_key), true))
1022 clearDomStoragePreference.setIcon(R.drawable.clear_dom_storage_enabled)
1024 clearDomStoragePreference.setIcon(R.drawable.clear_dom_storage_disabled)
1027 getString(R.string.clear_form_data_key) -> {
1029 if (sharedPreferences.getBoolean(getString(R.string.clear_form_data_key), true))
1030 clearFormDataPreference.setIcon(R.drawable.clear_form_data_enabled)
1032 clearFormDataPreference.setIcon(R.drawable.clear_form_data_disabled)
1035 getString(R.string.clear_logcat_key) -> {
1037 if (sharedPreferences.getBoolean(getString(R.string.clear_logcat_key), true))
1038 clearLogcatPreference.setIcon(R.drawable.clear_logcat_enabled)
1040 clearLogcatPreference.setIcon(R.drawable.clear_logcat_disabled)
1043 getString(R.string.clear_cache_key) -> {
1045 if (sharedPreferences.getBoolean(getString(R.string.clear_cache_key), true))
1046 clearCachePreference.setIcon(R.drawable.clear_cache_enabled)
1048 clearCachePreference.setIcon(R.drawable.clear_cache_disabled)
1051 getString(R.string.homepage_key) -> {
1052 // Set the new homepage URL as the summary text for the Homepage preference.
1053 homepagePreference.summary = sharedPreferences.getString(getString(R.string.homepage_key), getString(R.string.homepage_default_value))
1056 getString(R.string.font_size_key) -> {
1057 // Update the font size summary text.
1058 fontSizePreference.summary = sharedPreferences.getString(getString(R.string.font_size_key), getString(R.string.font_size_default_value)) + "%"
1061 getString(R.string.open_intents_in_new_tab_key) -> {
1063 if (sharedPreferences.getBoolean(getString(R.string.open_intents_in_new_tab_key), true))
1064 openIntentsInNewTabPreference.setIcon(R.drawable.tab_enabled)
1066 openIntentsInNewTabPreference.setIcon(R.drawable.tab_disabled)
1069 getString(R.string.swipe_to_refresh_key) -> {
1071 if (sharedPreferences.getBoolean(getString(R.string.swipe_to_refresh_key), true))
1072 swipeToRefreshPreference.setIcon(R.drawable.refresh_enabled)
1074 swipeToRefreshPreference.setIcon(R.drawable.refresh_disabled)
1077 getString(R.string.download_provider_key) -> {
1078 // Set the summary text for the download provider preference.
1079 downloadProviderPreference.summary = when (sharedPreferences.getString(getString(R.string.download_provider_key), getString(R.string.download_provider_default_value))) {
1080 downloadProviderEntryValuesStringArray[0] -> getString(R.string.download_with_privacy_browser) // Privacy Browser is selected.
1081 downloadProviderEntryValuesStringArray[1] -> getString(R.string.download_with_android_download_manager) // Android download manager is selected.
1082 else -> getString(R.string.download_with_external_app) // External app is selected.
1086 getString(R.string.scroll_app_bar_key) -> {
1088 if (sharedPreferences.getBoolean(getString(R.string.scroll_app_bar_key), false))
1089 scrollAppBarPreference.setIcon(R.drawable.app_bar_enabled)
1091 scrollAppBarPreference.setIcon(R.drawable.app_bar_disabled)
1094 getString(R.string.bottom_app_bar_key) -> {
1096 if (sharedPreferences.getBoolean(getString(R.string.bottom_app_bar_key), false))
1097 bottomAppBarPreference.setIcon(R.drawable.bottom_app_bar_enabled)
1099 bottomAppBarPreference.setIcon(R.drawable.bottom_app_bar_disabled)
1101 // Restart Privacy Browser.
1102 restartPrivacyBrowser()
1105 getString(R.string.display_additional_app_bar_icons_key) -> {
1107 if (sharedPreferences.getBoolean(getString(R.string.display_additional_app_bar_icons_key), false))
1108 displayAdditionalAppBarIconsPreference.setIcon(R.drawable.more_enabled)
1110 displayAdditionalAppBarIconsPreference.setIcon(R.drawable.more_disabled)
1112 // Restart Privacy Browser.
1113 restartPrivacyBrowser()
1116 getString(R.string.app_theme_key) -> {
1117 // Get the app theme entry number that matches the current app theme.
1118 val appThemeEntryNumber: Int = when (sharedPreferences.getString(getString(R.string.app_theme_key), getString(R.string.app_theme_default_value))) {
1119 appThemeEntryValuesStringArray[1] -> 1 // The light theme is selected.
1120 appThemeEntryValuesStringArray[2] -> 2 // The dark theme is selected.
1121 else -> 0 // The system default theme is selected.
1124 // Update the system according to the new theme.
1125 when (appThemeEntryNumber) {
1126 0 -> { // The system default theme is selected.
1127 // Update the theme preference summary text.
1128 appThemePreference.summary = appThemeEntriesStringArray[0]
1130 // Apply the new theme.
1131 if (Build.VERSION.SDK_INT >= 28) { // The system default theme is supported.
1132 // Follow the system default theme.
1133 AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
1134 } else { // The system default theme is not supported.
1135 // Follow the battery saver mode.
1136 AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_AUTO_BATTERY)
1140 1 -> { // The light theme is selected.
1141 // Update the theme preference summary text.
1142 appThemePreference.summary = appThemeEntriesStringArray[1]
1144 // Apply the new theme.
1145 AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
1148 2 -> { // The dark theme is selected.
1149 // Update the theme preference summary text.
1150 appThemePreference.summary = appThemeEntriesStringArray[2]
1152 // Apply the new theme.
1153 AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
1157 // Enable the WebView theme preference if the app theme is not set to light. Google does not allow light themes to display dark WebViews.
1158 webViewThemePreference.isEnabled = (appThemeEntryNumber != 1)
1160 // Get the webView theme entry number that matches the new WebView theme.
1161 val webViewThemeEntryNumber: Int = when (sharedPreferences.getString(getString(R.string.webview_theme_key), getString(R.string.webview_theme_default_value))) {
1162 webViewThemeEntriesStringArray[1] -> 1 // The light theme is selected.
1163 webViewThemeEntryValuesStringArray[2] -> 2 // The dark theme is selected.
1164 else -> 0 // The system default theme is selected.
1167 // Update the WebView theme icon.
1168 if (webViewThemePreference.isEnabled) { // The WebView theme preference is enabled.
1169 when (webViewThemeEntryNumber) {
1170 // The system default WebView theme is selected.
1172 // Get the current theme status.
1173 val currentThemeStatus = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
1175 // Set the icon according to the app theme.
1176 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO)
1177 webViewThemePreference.setIcon(R.drawable.webview_light_theme)
1179 webViewThemePreference.setIcon(R.drawable.webview_dark_theme)
1182 // The light WebView theme is selected.
1185 webViewThemePreference.setIcon(R.drawable.webview_light_theme)
1188 // The dark WebView theme is selected.
1191 webViewThemePreference.setIcon(R.drawable.webview_dark_theme)
1194 } else { // The WebView theme preference is disabled.
1195 webViewThemePreference.setIcon(R.drawable.webview_theme_ghosted)
1199 getString(R.string.webview_theme_key) -> {
1200 // Get the webView theme entry number that matches the new WebView theme.
1201 val newWebViewThemeEntryNumber: Int = when (sharedPreferences.getString(getString(R.string.webview_theme_key), getString(R.string.webview_theme_default_value))) {
1202 webViewThemeEntriesStringArray[1] -> 1 // The light theme is selected.
1203 webViewThemeEntryValuesStringArray[2] -> 2 // The dark theme is selected.
1204 else -> 0 // The system default theme is selected.
1207 // Update the WebView theme icon.
1208 when (newWebViewThemeEntryNumber) {
1209 // The system default WebView theme is selected.
1211 // Get the current theme status.
1212 val currentThemeStatus = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
1215 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO)
1216 webViewThemePreference.setIcon(R.drawable.webview_light_theme)
1218 webViewThemePreference.setIcon(R.drawable.webview_dark_theme)
1221 // The light WebView theme is selected.
1224 webViewThemePreference.setIcon(R.drawable.webview_light_theme)
1227 // The dark WebView theme is selected.
1230 webViewThemePreference.setIcon(R.drawable.webview_dark_theme)
1234 // Set the current theme as the summary text for the preference.
1235 webViewThemePreference.summary = webViewThemeEntriesStringArray[newWebViewThemeEntryNumber]
1238 getString(R.string.wide_viewport_key) -> {
1240 if (sharedPreferences.getBoolean(getString(R.string.wide_viewport_key), true))
1241 wideViewportPreference.setIcon(R.drawable.wide_viewport_enabled)
1243 wideViewportPreference.setIcon(R.drawable.wide_viewport_disabled)
1246 getString(R.string.display_webpage_images_key) -> {
1248 if (sharedPreferences.getBoolean(getString(R.string.display_webpage_images_key), true))
1249 displayWebpageImagesPreference.setIcon(R.drawable.images_enabled)
1251 displayWebpageImagesPreference.setIcon(R.drawable.images_disabled)
1257 private fun restartPrivacyBrowser() {
1258 // Create an intent to restart Privacy Browser.
1259 val restartIntent = requireActivity().parentActivityIntent!!
1261 // `Intent.FLAG_ACTIVITY_CLEAR_TASK` removes all activities from the stack. It requires `Intent.FLAG_ACTIVITY_NEW_TASK`.
1262 restartIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
1264 // Create a handler to restart the activity.
1265 val restartHandler = Handler(Looper.getMainLooper())
1267 // Create a runnable to restart the activity.
1268 val restartRunnable = Runnable {
1269 // Restart the activity.
1270 startActivity(restartIntent)
1272 // Kill this instance of Privacy Browser. Otherwise, the app exhibits sporadic behavior after the restart.
1276 // Restart the activity after 400 milliseconds, so that the app has enough time to save the change to the preference.
1277 restartHandler.postDelayed(restartRunnable, 400)