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 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)
172 displayUnderCutoutsPreference.dependency = getString(R.string.full_screen_browsing_mode_key)
174 // Get strings from the preferences.
175 val userAgentName = sharedPreferences.getString(getString(R.string.user_agent_key), getString(R.string.user_agent_default_value))
176 val searchString = sharedPreferences.getString(getString(R.string.search_key), getString(R.string.search_default_value))
177 val proxyString = sharedPreferences.getString(getString(R.string.proxy_key), getString(R.string.proxy_default_value))
179 // Get booleans that are used in multiple places from the preferences.
180 val javaScriptEnabled = sharedPreferences.getBoolean(getString(R.string.javascript_key), false)
181 val fanboyAnnoyanceListEnabled = sharedPreferences.getBoolean(getString(R.string.fanboys_annoyance_list_key), true)
182 val fanboySocialBlockingEnabled = sharedPreferences.getBoolean(getString(R.string.fanboys_social_blocking_list_key), true)
183 val fullScreenBrowsingMode = sharedPreferences.getBoolean(getString(R.string.full_screen_browsing_mode_key), false)
184 val clearEverything = sharedPreferences.getBoolean(getString(R.string.clear_everything_key), true)
186 // Remove the form data preferences if the API is >= 26 as they no longer do anything.
187 if (Build.VERSION.SDK_INT >= 26) {
188 // Get handles for the categories.
189 val privacyCategory = findPreference<PreferenceCategory>(getString(R.string.privacy_category_key))!!
190 val clearAndExitCategory = findPreference<PreferenceCategory>(getString(R.string.clear_and_exit_category_key))!!
192 // Remove the form data preferences.
193 privacyCategory.removePreference(formDataPreference)
194 clearAndExitCategory.removePreference(clearFormDataPreference)
197 // Only enable Fanboy's social blocking list preference if Fanboy's annoyance list is disabled.
198 fanboySocialBlockingListPreference.isEnabled = !fanboyAnnoyanceListEnabled
201 // Inflate a WebView to get the default user agent.
202 val inflater = requireActivity().layoutInflater
204 // `@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.
205 @SuppressLint("InflateParams") val bareWebViewLayout = inflater.inflate(R.layout.bare_webview, null, false)
207 // Get a handle for the bare WebView.
208 val bareWebView = bareWebViewLayout.findViewById<WebView>(R.id.bare_webview)
210 // Get the default user agent.
211 defaultUserAgent = bareWebView.settings.userAgentString
213 // Get the user agent arrays.
214 userAgentNamesArray = ArrayAdapter.createFromResource(requireContext(), R.array.user_agent_names, R.layout.spinner_item)
215 translatedUserAgentNamesArray = resources.getStringArray(R.array.translated_user_agent_names)
216 userAgentDataArray = resources.getStringArray(R.array.user_agent_data)
218 // Populate the user agent summary.
219 when (val userAgentArrayPosition = userAgentNamesArray.getPosition(userAgentName)) {
220 // The user agent name is not on the canonical list.
221 // 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.
222 UNRECOGNIZED_USER_AGENT -> userAgentPreference.summary = userAgentName
224 // Get the user agent text from the webview (which changes based on the version of Android and WebView installed).
225 SETTINGS_WEBVIEW_DEFAULT_USER_AGENT -> userAgentPreference.summary = "${translatedUserAgentNamesArray[userAgentArrayPosition]}:\n$defaultUserAgent"
227 // Display the custom user agent.
228 SETTINGS_CUSTOM_USER_AGENT -> userAgentPreference.setSummary(R.string.custom_user_agent)
230 // Get the user agent summary from the user agent data array.
231 else -> userAgentPreference.summary = "${translatedUserAgentNamesArray[userAgentArrayPosition]}:\n${userAgentDataArray[userAgentArrayPosition]}"
234 // Set the summary text for the custom user agent preference.
235 customUserAgentPreference.summary = sharedPreferences.getString(getString(R.string.custom_user_agent_key), getString(R.string.custom_user_agent_default_value))
237 // Only enable the custom user agent preference if the user agent is set to custom.
238 customUserAgentPreference.isEnabled = (userAgentPreference.summary == getString(R.string.custom_user_agent))
240 // Set the search URL as the summary text for the search preference when the preference screen is loaded.
241 if (searchString == getString(R.string.custom_url_item)) {
242 // Use R.string.custom_url, which will be translated, instead of the array value, which will not.
243 searchPreference.setSummary(R.string.custom_url)
245 // Set the array value as the summary text.
246 searchPreference.summary = searchString
249 // Set the summary text for the search custom URL (the default is `""`).
250 searchCustomURLPreference.summary = sharedPreferences.getString(getString(R.string.search_custom_url_key), getString(R.string.search_custom_url_default_value))
252 // Only enable the search custom URL preference if the search is set to a custom URL.
253 searchCustomURLPreference.isEnabled = (searchString == getString(R.string.custom_url_item))
255 // Set the summary text for the proxy preference.
256 proxyPreference.summary = when (proxyString) {
257 ProxyHelper.NONE -> getString(R.string.no_proxy_enabled)
258 ProxyHelper.TOR -> getString(R.string.tor_enabled)
259 ProxyHelper.I2P -> getString(R.string.i2p_enabled)
260 ProxyHelper.CUSTOM -> getString(R.string.custom_proxy)
261 else -> getString(R.string.no_proxy_enabled)
264 // Set the summary text for the custom proxy URL.
265 proxyCustomUrlPreference.summary = sharedPreferences.getString(getString(R.string.proxy_custom_url_key), getString(R.string.proxy_custom_url_default_value))
267 // Only enable the custom proxy URL if a custom proxy is selected.
268 proxyCustomUrlPreference.isEnabled = proxyString == ProxyHelper.CUSTOM
270 // Set the status of the clear and exit preferences.
271 clearCookiesPreference.isEnabled = !clearEverything
272 clearDomStoragePreference.isEnabled = !clearEverything
273 clearFormDataPreference.isEnabled = !clearEverything // Clear form data can be removed once the minimum API is >= 26.
274 clearLogcatPreference.isEnabled = !clearEverything
275 clearCachePreference.isEnabled = !clearEverything
277 // Set the homepage URL as the summary text for the homepage preference.
278 homepagePreference.summary = sharedPreferences.getString(getString(R.string.homepage_key), getString(R.string.homepage_default_value))
280 // Set the font size as the summary text for the preference.
281 fontSizePreference.summary = sharedPreferences.getString(getString(R.string.font_size_key), getString(R.string.font_size_default_value)) + "%"
283 // Get the app theme string arrays.
284 appThemeEntriesStringArray = resources.getStringArray(R.array.app_theme_entries)
285 appThemeEntryValuesStringArray = resources.getStringArray(R.array.app_theme_entry_values)
287 // Get the app theme entry number that matches the current app theme.
288 val appThemeEntryNumber: Int = when (sharedPreferences.getString(getString(R.string.app_theme_key), getString(R.string.app_theme_default_value))) {
289 appThemeEntryValuesStringArray[1] -> 1 // The light theme is selected.
290 appThemeEntryValuesStringArray[2] -> 2 // The dark theme is selected.
291 else -> 0 // The system default theme is selected.
294 // Set the current theme as the summary text for the preference.
295 appThemePreference.summary = appThemeEntriesStringArray[appThemeEntryNumber]
297 // Enable the WebView theme preference if the app theme is not set to light. Google does not allow light themes to display dark WebViews.
298 webViewThemePreference.isEnabled = (appThemeEntryNumber != 1)
300 // Get the WebView theme string arrays.
301 webViewThemeEntriesStringArray = resources.getStringArray(R.array.webview_theme_entries)
302 webViewThemeEntryValuesStringArray = resources.getStringArray(R.array.webview_theme_entry_values)
304 // Get the WebView theme entry number that matches the current WebView theme.
305 val webViewThemeEntryNumber: Int = when (sharedPreferences.getString(getString(R.string.webview_theme_key), getString(R.string.webview_theme_default_value))) {
306 webViewThemeEntryValuesStringArray[1] -> 1 // The light theme is selected.
307 webViewThemeEntryValuesStringArray[2] -> 2 // The dark theme is selected.
308 else -> 0 // The system default theme is selected.
311 // Set the current theme as the summary text for the preference.
312 webViewThemePreference.summary = webViewThemeEntriesStringArray[webViewThemeEntryNumber]
314 // Set the JavaScript icon.
315 if (javaScriptEnabled)
316 javaScriptPreference.setIcon(R.drawable.javascript_enabled)
318 javaScriptPreference.setIcon(R.drawable.privacy_mode)
320 // Set the cookies icon.
321 if (sharedPreferences.getBoolean(getString(R.string.cookies_key), false))
322 cookiesPreference.setIcon(R.drawable.cookies_enabled)
324 cookiesPreference.setIcon(R.drawable.cookies_disabled)
326 // Set the DOM storage icon.
327 if (javaScriptEnabled) { // JavaScript is enabled.
328 if (sharedPreferences.getBoolean(getString(R.string.dom_storage_key), false)) // DOM storage is enabled.
329 domStoragePreference.setIcon(R.drawable.dom_storage_enabled)
330 else // DOM storage is disabled.
331 domStoragePreference.setIcon(R.drawable.dom_storage_disabled)
332 } else { // JavaScript is disabled. DOM storage should be ghosted.
333 domStoragePreference.setIcon(R.drawable.dom_storage_ghosted)
336 // Set the save form data icon if API < 26. Save form data has no effect on API >= 26.
337 if (Build.VERSION.SDK_INT < 26) {
338 if (sharedPreferences.getBoolean(getString(R.string.save_form_data_key), false))
339 formDataPreference.setIcon(R.drawable.form_data_enabled)
341 formDataPreference.setIcon(R.drawable.form_data_disabled)
344 // Set the custom user agent icon.
345 if (customUserAgentPreference.isEnabled)
346 customUserAgentPreference.setIcon(R.drawable.custom_user_agent_enabled)
348 customUserAgentPreference.setIcon(R.drawable.custom_user_agent_ghosted)
350 // Set the incognito mode icon.
351 if (sharedPreferences.getBoolean(getString(R.string.incognito_mode_key), false))
352 incognitoModePreference.setIcon(R.drawable.incognito_mode_enabled)
354 incognitoModePreference.setIcon(R.drawable.incognito_mode_disabled)
356 // Set the allow screenshots icon.
357 if (sharedPreferences.getBoolean(getString(R.string.allow_screenshots_key), false))
358 allowScreenshotsPreference.setIcon(R.drawable.allow_screenshots_enabled)
360 allowScreenshotsPreference.setIcon(R.drawable.allow_screenshots_disabled)
362 // Set the EasyList icon.
363 if (sharedPreferences.getBoolean(getString(R.string.easylist_key), true))
364 easyListPreference.setIcon(R.drawable.block_ads_enabled)
366 easyListPreference.setIcon(R.drawable.block_ads_disabled)
368 // Set the EasyPrivacy icon.
369 if (sharedPreferences.getBoolean(getString(R.string.easyprivacy_key), true))
370 easyPrivacyPreference.setIcon(R.drawable.block_tracking_enabled)
372 easyPrivacyPreference.setIcon(R.drawable.block_tracking_disabled)
374 // Set the Fanboy lists icons.
375 if (fanboyAnnoyanceListEnabled) {
376 // Set the Fanboy annoyance list icon.
377 fanboyAnnoyanceListPreference.setIcon(R.drawable.social_media_enabled)
379 // Set the Fanboy social blocking list icon.
380 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_ghosted)
382 // Set the Fanboy annoyance list icon.
383 fanboyAnnoyanceListPreference.setIcon(R.drawable.social_media_disabled)
385 // Set the Fanboy social blocking list icon.
386 if (fanboySocialBlockingEnabled)
387 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_enabled)
389 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_disabled)
392 // Set the UltraList icon.
393 if (sharedPreferences.getBoolean(getString(R.string.ultralist_key), true))
394 ultraListPreference.setIcon(R.drawable.block_ads_enabled)
396 ultraListPreference.setIcon(R.drawable.block_ads_disabled)
398 // Set the UltraPrivacy icon.
399 if (sharedPreferences.getBoolean(getString(R.string.ultraprivacy_key), true))
400 ultraPrivacyPreference.setIcon(R.drawable.block_tracking_enabled)
402 ultraPrivacyPreference.setIcon(R.drawable.block_tracking_disabled)
404 // Set the block all third-party requests icon.
405 if (sharedPreferences.getBoolean(getString(R.string.block_all_third_party_requests), false))
406 blockAllThirdPartyRequestsPreference.setIcon(R.drawable.block_all_third_party_requests_enabled)
408 blockAllThirdPartyRequestsPreference.setIcon(R.drawable.block_all_third_party_requests_disabled)
410 // Set the Tracking Queries icon.
411 if (sharedPreferences.getBoolean(getString(R.string.tracking_queries_key), true))
412 trackingQueriesPreference.setIcon(R.drawable.modify_url_enabled)
414 trackingQueriesPreference.setIcon(R.drawable.modify_url_disabled)
416 // Set the AMP Redirects icon.
417 if (sharedPreferences.getBoolean(getString(R.string.amp_redirects_key), true))
418 ampRedirectsPreference.setIcon(R.drawable.modify_url_enabled)
420 ampRedirectsPreference.setIcon(R.drawable.modify_url_disabled)
422 // Set the search custom URL icon.
423 if (searchCustomURLPreference.isEnabled)
424 searchCustomURLPreference.setIcon(R.drawable.search_custom_enabled)
426 searchCustomURLPreference.setIcon(R.drawable.search_custom_ghosted)
428 // Set the proxy icons according to the theme and status.
429 if (proxyString == ProxyHelper.NONE) { // Proxying is disabled.
430 // Set the main proxy icon to be disabled.
431 proxyPreference.setIcon(R.drawable.proxy_disabled)
433 // Set the custom proxy URL icon to be ghosted.
434 proxyCustomUrlPreference.setIcon(R.drawable.proxy_ghosted)
435 } else { // Proxying is enabled.
436 // Set the main proxy icon to be enabled.
437 proxyPreference.setIcon(R.drawable.proxy_enabled)
439 // Set the custom proxy URL icon according to its status.
440 if (proxyCustomUrlPreference.isEnabled)
441 proxyCustomUrlPreference.setIcon(R.drawable.proxy_enabled)
443 proxyCustomUrlPreference.setIcon(R.drawable.proxy_ghosted)
446 // Set the full-screen browsing mode icons.
447 if (fullScreenBrowsingMode) { // Full-screen browsing mode is enabled.
448 // Set the full screen browsing mode preference icon.
449 fullScreenBrowsingModePreference.setIcon(R.drawable.full_screen_enabled)
451 // Set the hide app bar icon.
452 if (sharedPreferences.getBoolean(getString(R.string.hide_app_bar_key), true))
453 hideAppBarPreference.setIcon(R.drawable.app_bar_enabled)
455 hideAppBarPreference.setIcon(R.drawable.app_bar_disabled)
456 } else { // Full screen browsing mode is disabled.
458 fullScreenBrowsingModePreference.setIcon(R.drawable.full_screen_disabled)
459 hideAppBarPreference.setIcon(R.drawable.app_bar_ghosted)
462 // Set the display under cutouts icon.
463 if (sharedPreferences.getBoolean(getString(R.string.display_under_cutouts_key), false))
464 displayUnderCutoutsPreference.setIcon(R.drawable.display_under_cutouts_enabled)
466 displayUnderCutoutsPreference.setIcon(R.drawable.display_under_cutouts_disabled)
468 // Set the clear everything icon.
469 if (clearEverything) {
470 clearEverythingPreference.setIcon(R.drawable.clear_everything_enabled)
472 clearEverythingPreference.setIcon(R.drawable.clear_everything_disabled)
475 // Set the clear cookies icon.
476 if (clearEverything || sharedPreferences.getBoolean(getString(R.string.clear_cookies_key), true))
477 clearCookiesPreference.setIcon(R.drawable.clear_cookies_enabled)
479 clearCookiesPreference.setIcon(R.drawable.clear_cookies_disabled)
481 // Set the clear DOM storage icon.
482 if (clearEverything || sharedPreferences.getBoolean(getString(R.string.clear_dom_storage_key), true))
483 clearDomStoragePreference.setIcon(R.drawable.clear_dom_storage_enabled)
485 clearDomStoragePreference.setIcon(R.drawable.clear_dom_storage_disabled)
487 // Set the clear form data icon if the API < 26. It has no effect on newer versions of Android.
488 if (Build.VERSION.SDK_INT < 26) {
489 if (clearEverything || sharedPreferences.getBoolean(getString(R.string.clear_form_data_key), true))
490 clearFormDataPreference.setIcon(R.drawable.clear_form_data_enabled)
492 clearFormDataPreference.setIcon(R.drawable.clear_form_data_disabled)
495 // Set the clear logcat icon.
496 if (clearEverything || sharedPreferences.getBoolean(getString(R.string.clear_logcat_key), true))
497 clearLogcatPreference.setIcon(R.drawable.clear_logcat_enabled)
499 clearLogcatPreference.setIcon(R.drawable.clear_logcat_disabled)
501 // Set the clear cache icon.
502 if (clearEverything || sharedPreferences.getBoolean(getString(R.string.clear_cache_key), true))
503 clearCachePreference.setIcon(R.drawable.clear_cache_enabled)
505 clearCachePreference.setIcon(R.drawable.clear_cache_disabled)
507 // Set the open intents in new tab icon.
508 if (sharedPreferences.getBoolean(getString(R.string.open_intents_in_new_tab_key), true))
509 openIntentsInNewTabPreference.setIcon(R.drawable.tab_enabled)
511 openIntentsInNewTabPreference.setIcon(R.drawable.tab_disabled)
513 // Set the swipe to refresh icon.
514 if (sharedPreferences.getBoolean(getString(R.string.swipe_to_refresh_key), true))
515 swipeToRefreshPreference.setIcon(R.drawable.refresh_enabled)
517 swipeToRefreshPreference.setIcon(R.drawable.refresh_disabled)
519 // Set the download with external app icon.
520 if (sharedPreferences.getBoolean(getString(R.string.download_with_external_app_key), false))
521 downloadWithExternalAppPreference.setIcon(R.drawable.download_with_external_app_enabled)
523 downloadWithExternalAppPreference.setIcon(R.drawable.download_with_external_app_disabled)
525 // Set the scroll app bar icon.
526 if (sharedPreferences.getBoolean(getString(R.string.scroll_app_bar_key), false))
527 scrollAppBarPreference.setIcon(R.drawable.app_bar_enabled)
529 scrollAppBarPreference.setIcon(R.drawable.app_bar_disabled)
531 // Set the bottom app bar icon.
532 if (sharedPreferences.getBoolean(getString(R.string.bottom_app_bar_key), false))
533 bottomAppBarPreference.setIcon(R.drawable.bottom_app_bar_enabled)
535 bottomAppBarPreference.setIcon(R.drawable.bottom_app_bar_disabled)
537 // Set the display additional app bar icons icon.
538 if (sharedPreferences.getBoolean(getString(R.string.display_additional_app_bar_icons_key), false))
539 displayAdditionalAppBarIconsPreference.setIcon(R.drawable.more_enabled)
541 displayAdditionalAppBarIconsPreference.setIcon(R.drawable.more_disabled)
543 // Set the WebView theme icon.
544 if (webViewThemePreference.isEnabled) { // The WebView theme preference is enabled.
545 when (webViewThemeEntryNumber) {
546 // The system default WebView theme is selected.
548 // Get the current theme status.
549 val currentThemeStatus = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
551 // Set the icon according to the app theme.
552 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO)
553 webViewThemePreference.setIcon(R.drawable.webview_light_theme)
555 webViewThemePreference.setIcon(R.drawable.webview_dark_theme)
558 // The light WebView theme is selected.
561 webViewThemePreference.setIcon(R.drawable.webview_light_theme)
564 // The dark WebView theme is selected.
567 webViewThemePreference.setIcon(R.drawable.webview_dark_theme)
570 } else { // The WebView theme preference is disabled.
571 webViewThemePreference.setIcon(R.drawable.webview_theme_ghosted)
574 // Set the wide viewport icon.
575 if (sharedPreferences.getBoolean(getString(R.string.wide_viewport_key), true))
576 wideViewportPreference.setIcon(R.drawable.wide_viewport_enabled)
578 wideViewportPreference.setIcon(R.drawable.wide_viewport_disabled)
580 // Set the display webpage images icon.
581 if (sharedPreferences.getBoolean(getString(R.string.display_webpage_images_key), true))
582 displayWebpageImagesPreference.setIcon(R.drawable.images_enabled)
584 displayWebpageImagesPreference.setIcon(R.drawable.images_disabled)
587 // The listener should be unregistered when the app is paused.
588 override fun onPause() {
589 // Run the default commands.
592 // Get a handle for the shared preferences.
593 val sharedPreferences = preferenceScreen.sharedPreferences!!
595 // Unregister the shared preference listener.
596 sharedPreferences.unregisterOnSharedPreferenceChangeListener(sharedPreferenceChangeListener)
599 // The listener should be re-registered when the app is resumed.
600 override fun onResume() {
601 // Run the default commands.
604 // Get a new shared preference change listener.
605 sharedPreferenceChangeListener = getSharedPreferenceChangeListener()
607 // Get a handle for the shared preferences.
608 val sharedPreferences = preferenceScreen.sharedPreferences!!
610 // Re-register the shared preference listener.
611 sharedPreferences.registerOnSharedPreferenceChangeListener(sharedPreferenceChangeListener)
613 // Restore the scroll position if the fragment has been restarted.
614 if (fragmentRestarted) {
615 // Reset the fragment restarted flag.
616 fragmentRestarted = false
618 // Set the scroll position.
619 listView.post { listView.smoothScrollBy(0, scrollY) }
623 override fun onSaveInstanceState(savedInstanceState: Bundle) {
624 // Run the default commands.
625 super.onSaveInstanceState(savedInstanceState)
627 // Save the scroll position.
628 savedInstanceState.putInt(SCROLL_Y, listView.computeVerticalScrollOffset())
631 private fun getSharedPreferenceChangeListener(): OnSharedPreferenceChangeListener {
632 // Return the shared preference change listener.
633 return OnSharedPreferenceChangeListener { sharedPreferences: SharedPreferences, key: String? ->
635 getString(R.string.javascript_key) -> {
636 // Update the icons and the DOM storage preference status.
637 if (sharedPreferences.getBoolean(getString(R.string.javascript_key), false)) { // The JavaScript preference is enabled.
638 // Update the icon for the JavaScript preference.
639 javaScriptPreference.setIcon(R.drawable.javascript_enabled)
641 // Update the status of the DOM storage preference.
642 domStoragePreference.isEnabled = true
644 // Update the icon for the DOM storage preference.
645 if (sharedPreferences.getBoolean(getString(R.string.dom_storage_key), false))
646 domStoragePreference.setIcon(R.drawable.dom_storage_enabled)
648 domStoragePreference.setIcon(R.drawable.dom_storage_disabled)
649 } else { // The JavaScript preference is disabled.
650 // Update the icon for the JavaScript preference.
651 javaScriptPreference.setIcon(R.drawable.privacy_mode)
653 // Update the status of the DOM storage preference.
654 domStoragePreference.isEnabled = false
656 // Set the icon for DOM storage preference to be ghosted.
657 domStoragePreference.setIcon(R.drawable.dom_storage_ghosted)
661 getString(R.string.cookies_key) -> {
663 if (sharedPreferences.getBoolean(getString(R.string.cookies_key), false))
664 cookiesPreference.setIcon(R.drawable.cookies_enabled)
666 cookiesPreference.setIcon(R.drawable.cookies_disabled)
669 getString(R.string.dom_storage_key) -> {
671 if (sharedPreferences.getBoolean(getString(R.string.dom_storage_key), false))
672 domStoragePreference.setIcon(R.drawable.dom_storage_enabled)
674 domStoragePreference.setIcon(R.drawable.dom_storage_disabled)
677 getString(R.string.save_form_data_key) -> { // Saved form data can be removed once the minimum API >= 26.
679 if (sharedPreferences.getBoolean(getString(R.string.save_form_data_key), false))
680 formDataPreference.setIcon(R.drawable.form_data_enabled)
682 formDataPreference.setIcon(R.drawable.form_data_disabled)
685 getString(R.string.user_agent_key) -> {
686 // Get the new user agent name.
687 val newUserAgentName = sharedPreferences.getString(getString(R.string.user_agent_key), getString(R.string.user_agent_default_value))
689 // Get the array position for the new user agent name.
690 val newUserAgentArrayPosition = userAgentNamesArray.getPosition(newUserAgentName)
692 // Get the translated new user agent name.
693 val translatedNewUserAgentName = translatedUserAgentNamesArray[newUserAgentArrayPosition]
695 // Populate the user agent summary.
696 when (newUserAgentArrayPosition) {
697 SETTINGS_WEBVIEW_DEFAULT_USER_AGENT -> {
698 // Get the user agent text from the webview (which changes based on the version of Android and WebView installed).
699 userAgentPreference.summary = "$translatedNewUserAgentName:\n$defaultUserAgent"
701 // Disable the custom user agent preference.
702 customUserAgentPreference.isEnabled = false
704 // Set the custom user agent preference icon.
705 customUserAgentPreference.setIcon(R.drawable.custom_user_agent_ghosted)
708 SETTINGS_CUSTOM_USER_AGENT -> {
709 // Set the summary text.
710 userAgentPreference.setSummary(R.string.custom_user_agent)
712 // Enable the custom user agent preference.
713 customUserAgentPreference.isEnabled = true
715 // Set the custom user agent preference icon.
716 customUserAgentPreference.setIcon(R.drawable.custom_user_agent_enabled)
720 // Get the user agent summary from the user agent data array.
721 userAgentPreference.summary = "$translatedNewUserAgentName:\n${userAgentDataArray[newUserAgentArrayPosition]}"
723 // Disable the custom user agent preference.
724 customUserAgentPreference.isEnabled = false
726 // Set the custom user agent preference icon.
727 customUserAgentPreference.setIcon(R.drawable.custom_user_agent_ghosted)
732 getString(R.string.custom_user_agent_key) -> {
733 // Set the new custom user agent as the summary text for the preference.
734 customUserAgentPreference.summary = sharedPreferences.getString(getString(R.string.custom_user_agent_key), getString(R.string.custom_user_agent_default_value))
737 getString(R.string.incognito_mode_key) -> {
739 if (sharedPreferences.getBoolean(getString(R.string.incognito_mode_key), false))
740 incognitoModePreference.setIcon(R.drawable.incognito_mode_enabled)
742 incognitoModePreference.setIcon(R.drawable.incognito_mode_disabled)
745 getString(R.string.allow_screenshots_key) -> {
747 if (sharedPreferences.getBoolean(getString(R.string.allow_screenshots_key), false))
748 allowScreenshotsPreference.setIcon(R.drawable.allow_screenshots_enabled)
750 allowScreenshotsPreference.setIcon(R.drawable.allow_screenshots_disabled)
752 // Restart Privacy Browser.
753 restartPrivacyBrowser()
756 getString(R.string.easylist_key) -> {
758 if (sharedPreferences.getBoolean(getString(R.string.easylist_key), true))
759 easyListPreference.setIcon(R.drawable.block_ads_enabled)
761 easyListPreference.setIcon(R.drawable.block_ads_disabled)
764 getString(R.string.easyprivacy_key) -> {
766 if (sharedPreferences.getBoolean(getString(R.string.easyprivacy_key), true))
767 easyPrivacyPreference.setIcon(R.drawable.block_tracking_enabled)
769 easyPrivacyPreference.setIcon(R.drawable.block_tracking_disabled)
772 getString(R.string.fanboys_annoyance_list_key) -> {
773 // Get the current Fanboy settings.
774 val currentFanboyAnnoyanceList = sharedPreferences.getBoolean(getString(R.string.fanboys_annoyance_list_key), true)
775 val currentFanboySocialBlockingList = sharedPreferences.getBoolean(getString(R.string.fanboys_social_blocking_list_key), true)
777 // Update the Fanboy icons.
778 if (currentFanboyAnnoyanceList) { // Fanboy's annoyance list is enabled.
779 // Update the Fanboy's annoyance list icon.
780 fanboyAnnoyanceListPreference.setIcon(R.drawable.social_media_enabled)
782 // Update the Fanboy's social blocking list icon.
783 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_ghosted)
784 } else { // Fanboy's annoyance list is disabled.
785 // Update the Fanboy's annoyance list icon.
786 fanboyAnnoyanceListPreference.setIcon(R.drawable.social_media_disabled)
788 // Update the Fanboy's social blocking list icon.
789 if (currentFanboySocialBlockingList)
790 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_enabled)
792 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_disabled)
795 // Only enable Fanboy's social blocking list preference if Fanboy's annoyance list preference is disabled.
796 fanboySocialBlockingListPreference.isEnabled = !currentFanboyAnnoyanceList
799 getString(R.string.fanboys_social_blocking_list_key) -> {
801 if (sharedPreferences.getBoolean(getString(R.string.fanboys_social_blocking_list_key), true))
802 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_enabled)
804 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_disabled)
807 getString(R.string.ultralist_key) -> {
809 if (sharedPreferences.getBoolean(getString(R.string.ultralist_key), true))
810 ultraListPreference.setIcon(R.drawable.block_ads_enabled)
812 ultraListPreference.setIcon(R.drawable.block_ads_disabled)
815 getString(R.string.ultraprivacy_key) -> {
817 if (sharedPreferences.getBoolean(getString(R.string.ultraprivacy_key), true))
818 ultraPrivacyPreference.setIcon(R.drawable.block_tracking_enabled)
820 ultraPrivacyPreference.setIcon(R.drawable.block_tracking_disabled)
823 getString(R.string.block_all_third_party_requests_key) -> {
825 if (sharedPreferences.getBoolean(getString(R.string.block_all_third_party_requests_key), false)) {
826 blockAllThirdPartyRequestsPreference.setIcon(R.drawable.block_all_third_party_requests_enabled)
828 blockAllThirdPartyRequestsPreference.setIcon(R.drawable.block_all_third_party_requests_disabled)
832 getString(R.string.tracking_queries_key) -> {
834 if (sharedPreferences.getBoolean(getString(R.string.tracking_queries_key), true))
835 trackingQueriesPreference.setIcon(R.drawable.modify_url_enabled)
837 trackingQueriesPreference.setIcon(R.drawable.modify_url_disabled)
840 getString(R.string.amp_redirects_key) -> {
842 if (sharedPreferences.getBoolean(getString(R.string.amp_redirects_key), true))
843 ampRedirectsPreference.setIcon(R.drawable.modify_url_enabled)
845 ampRedirectsPreference.setIcon(R.drawable.modify_url_disabled)
848 getString(R.string.search_key) -> {
849 // Store the new search string.
850 val newSearchString = sharedPreferences.getString(getString(R.string.search_key), getString(R.string.search_default_value))
852 // Update the search and search custom URL preferences.
853 if (newSearchString == getString(R.string.custom_url_item)) { // A custom URL is selected.
854 // Set the summary text to `R.string.custom_url`, which is translated.
855 searchPreference.setSummary(R.string.custom_url)
857 // Enable the search custom URL preference.
858 searchCustomURLPreference.isEnabled = true
860 // Set the search custom URL preference icon.
861 searchCustomURLPreference.setIcon(R.drawable.search_custom_enabled)
862 } else { // A custom URL is not selected.
863 // Set the summary text to the new search string.
864 searchPreference.summary = newSearchString
866 // Disable the search custom URL Preference.
867 searchCustomURLPreference.isEnabled = false
869 // Set the search custom URL preference icon.
870 searchCustomURLPreference.setIcon(R.drawable.search_custom_ghosted)
874 getString(R.string.search_custom_url_key) -> {
875 // Set the new search custom URL as the summary text for the preference.
876 searchCustomURLPreference.summary = sharedPreferences.getString(getString(R.string.search_custom_url_key), getString(R.string.search_custom_url_default_value))
879 getString(R.string.proxy_key) -> {
880 // Get the current proxy string.
881 val currentProxyString = sharedPreferences.getString(getString(R.string.proxy_key), getString(R.string.proxy_default_value))
883 // Update the proxy preference summary text.
884 proxyPreference.summary = when (currentProxyString) {
885 ProxyHelper.NONE -> getString(R.string.no_proxy_enabled)
886 ProxyHelper.TOR -> getString(R.string.tor_enabled)
887 ProxyHelper.I2P -> getString(R.string.i2p_enabled)
888 ProxyHelper.CUSTOM -> getString(R.string.custom_proxy)
889 else -> getString(R.string.no_proxy_enabled)
892 // Update the status of the custom URL preference.
893 proxyCustomUrlPreference.isEnabled = currentProxyString == ProxyHelper.CUSTOM
896 if (currentProxyString == ProxyHelper.NONE) { // Proxying is disabled.
897 // Set the main proxy icon to be disabled
898 proxyPreference.setIcon(R.drawable.proxy_disabled)
900 // Set the custom proxy URL icon to be ghosted.
901 proxyCustomUrlPreference.setIcon(R.drawable.proxy_ghosted)
902 } else { // Proxying is enabled.
903 // Set the main proxy icon to be enabled.
904 proxyPreference.setIcon(R.drawable.proxy_enabled)
906 /// Set the custom proxy URL icon according to its status.
907 if (proxyCustomUrlPreference.isEnabled)
908 proxyCustomUrlPreference.setIcon(R.drawable.proxy_enabled)
910 proxyCustomUrlPreference.setIcon(R.drawable.proxy_ghosted)
914 getString(R.string.proxy_custom_url_key) -> {
915 // Set the summary text for the proxy custom URL.
916 proxyCustomUrlPreference.summary = sharedPreferences.getString(getString(R.string.proxy_custom_url_key), getString(R.string.proxy_custom_url_default_value))
919 getString(R.string.full_screen_browsing_mode_key) -> {
921 if (sharedPreferences.getBoolean(getString(R.string.full_screen_browsing_mode_key), false)) { // Full screen browsing is enabled.
922 // Set the full screen browsing mode preference icon.
923 fullScreenBrowsingModePreference.setIcon(R.drawable.full_screen_enabled)
925 // Set the hide app bar preference icon.
926 if (sharedPreferences.getBoolean(getString(R.string.hide_app_bar_key), true))
927 hideAppBarPreference.setIcon(R.drawable.app_bar_enabled)
929 hideAppBarPreference.setIcon(R.drawable.app_bar_disabled)
930 } else { // Full screen browsing is disabled.
932 fullScreenBrowsingModePreference.setIcon(R.drawable.full_screen_disabled)
933 hideAppBarPreference.setIcon(R.drawable.app_bar_ghosted)
937 getString(R.string.hide_app_bar_key) -> {
939 if (sharedPreferences.getBoolean(getString(R.string.hide_app_bar_key), true))
940 hideAppBarPreference.setIcon(R.drawable.app_bar_enabled)
942 hideAppBarPreference.setIcon(R.drawable.app_bar_disabled)
945 getString(R.string.display_under_cutouts_key) -> {
947 if (sharedPreferences.getBoolean(getString(R.string.display_under_cutouts_key), true))
948 displayUnderCutoutsPreference.setIcon(R.drawable.display_under_cutouts_enabled)
950 displayUnderCutoutsPreference.setIcon(R.drawable.display_under_cutouts_disabled)
952 // Restart Privacy Browser.
953 restartPrivacyBrowser()
956 getString(R.string.clear_everything_key) -> {
957 // Store the new clear everything status
958 val newClearEverythingBoolean = sharedPreferences.getBoolean(getString(R.string.clear_everything_key), true)
960 // Update the status of the clear and exit preferences.
961 clearCookiesPreference.isEnabled = !newClearEverythingBoolean
962 clearDomStoragePreference.isEnabled = !newClearEverythingBoolean
963 clearFormDataPreference.isEnabled = !newClearEverythingBoolean // Clear form data can be removed once the minimum API >= 26.
964 clearLogcatPreference.isEnabled = !newClearEverythingBoolean
965 clearCachePreference.isEnabled = !newClearEverythingBoolean
967 // Update the clear everything preference icon.
968 if (newClearEverythingBoolean)
969 clearEverythingPreference.setIcon(R.drawable.clear_everything_enabled)
971 clearEverythingPreference.setIcon(R.drawable.clear_everything_disabled)
973 // Update the clear cookies preference icon.
974 if (newClearEverythingBoolean || sharedPreferences.getBoolean(getString(R.string.clear_cookies_key), true))
975 clearCookiesPreference.setIcon(R.drawable.clear_cookies_enabled)
977 clearCookiesPreference.setIcon(R.drawable.clear_cookies_disabled)
979 // Update the clear dom storage preference icon.
980 if (newClearEverythingBoolean || sharedPreferences.getBoolean(getString(R.string.clear_dom_storage_key), true))
981 clearDomStoragePreference.setIcon(R.drawable.clear_dom_storage_enabled)
983 clearDomStoragePreference.setIcon(R.drawable.clear_dom_storage_disabled)
985 // Update the clear form data preference icon if the API < 26.
986 if (Build.VERSION.SDK_INT < 26) {
987 if (newClearEverythingBoolean || sharedPreferences.getBoolean(getString(R.string.clear_form_data_key), true))
988 clearFormDataPreference.setIcon(R.drawable.clear_form_data_enabled)
990 clearFormDataPreference.setIcon(R.drawable.clear_form_data_disabled)
993 // Update the clear logcat preference icon.
994 if (newClearEverythingBoolean || sharedPreferences.getBoolean(getString(R.string.clear_logcat_key), true))
995 clearLogcatPreference.setIcon(R.drawable.clear_logcat_enabled)
997 clearLogcatPreference.setIcon(R.drawable.clear_logcat_disabled)
999 // Update the clear cache preference icon.
1000 if (newClearEverythingBoolean || sharedPreferences.getBoolean(getString(R.string.clear_cache_key), true))
1001 clearCachePreference.setIcon(R.drawable.clear_cache_enabled)
1003 clearCachePreference.setIcon(R.drawable.clear_cache_disabled)
1006 getString(R.string.clear_cookies_key) -> {
1008 if (sharedPreferences.getBoolean(getString(R.string.clear_cookies_key), true))
1009 clearCookiesPreference.setIcon(R.drawable.clear_cookies_enabled)
1011 clearCookiesPreference.setIcon(R.drawable.clear_cookies_disabled)
1014 getString(R.string.clear_dom_storage_key) -> {
1016 if (sharedPreferences.getBoolean(getString(R.string.clear_dom_storage_key), true))
1017 clearDomStoragePreference.setIcon(R.drawable.clear_dom_storage_enabled)
1019 clearDomStoragePreference.setIcon(R.drawable.clear_dom_storage_disabled)
1022 getString(R.string.clear_form_data_key) -> {
1024 if (sharedPreferences.getBoolean(getString(R.string.clear_form_data_key), true))
1025 clearFormDataPreference.setIcon(R.drawable.clear_form_data_enabled)
1027 clearFormDataPreference.setIcon(R.drawable.clear_form_data_disabled)
1030 getString(R.string.clear_logcat_key) -> {
1032 if (sharedPreferences.getBoolean(getString(R.string.clear_logcat_key), true))
1033 clearLogcatPreference.setIcon(R.drawable.clear_logcat_enabled)
1035 clearLogcatPreference.setIcon(R.drawable.clear_logcat_disabled)
1038 getString(R.string.clear_cache_key) -> {
1040 if (sharedPreferences.getBoolean(getString(R.string.clear_cache_key), true))
1041 clearCachePreference.setIcon(R.drawable.clear_cache_enabled)
1043 clearCachePreference.setIcon(R.drawable.clear_cache_disabled)
1046 getString(R.string.homepage_key) -> {
1047 // Set the new homepage URL as the summary text for the Homepage preference.
1048 homepagePreference.summary = sharedPreferences.getString(getString(R.string.homepage_key), getString(R.string.homepage_default_value))
1051 getString(R.string.font_size_key) -> {
1052 // Update the font size summary text.
1053 fontSizePreference.summary = sharedPreferences.getString(getString(R.string.font_size_key), getString(R.string.font_size_default_value)) + "%"
1056 getString(R.string.open_intents_in_new_tab_key) -> {
1058 if (sharedPreferences.getBoolean(getString(R.string.open_intents_in_new_tab_key), true))
1059 openIntentsInNewTabPreference.setIcon(R.drawable.tab_enabled)
1061 openIntentsInNewTabPreference.setIcon(R.drawable.tab_disabled)
1064 getString(R.string.swipe_to_refresh_key) -> {
1066 if (sharedPreferences.getBoolean(getString(R.string.swipe_to_refresh_key), true))
1067 swipeToRefreshPreference.setIcon(R.drawable.refresh_enabled)
1069 swipeToRefreshPreference.setIcon(R.drawable.refresh_disabled)
1072 getString(R.string.download_with_external_app_key) -> {
1074 if (sharedPreferences.getBoolean(getString(R.string.download_with_external_app_key), false))
1075 downloadWithExternalAppPreference.setIcon(R.drawable.download_with_external_app_enabled)
1077 downloadWithExternalAppPreference.setIcon(R.drawable.download_with_external_app_disabled)
1080 getString(R.string.scroll_app_bar_key) -> {
1082 if (sharedPreferences.getBoolean(getString(R.string.scroll_app_bar_key), false))
1083 scrollAppBarPreference.setIcon(R.drawable.app_bar_enabled)
1085 scrollAppBarPreference.setIcon(R.drawable.app_bar_disabled)
1088 getString(R.string.bottom_app_bar_key) -> {
1090 if (sharedPreferences.getBoolean(getString(R.string.bottom_app_bar_key), false))
1091 bottomAppBarPreference.setIcon(R.drawable.bottom_app_bar_enabled)
1093 bottomAppBarPreference.setIcon(R.drawable.bottom_app_bar_disabled)
1095 // Restart Privacy Browser.
1096 restartPrivacyBrowser()
1099 getString(R.string.display_additional_app_bar_icons_key) -> {
1101 if (sharedPreferences.getBoolean(getString(R.string.display_additional_app_bar_icons_key), false))
1102 displayAdditionalAppBarIconsPreference.setIcon(R.drawable.more_enabled)
1104 displayAdditionalAppBarIconsPreference.setIcon(R.drawable.more_disabled)
1106 // Restart Privacy Browser.
1107 restartPrivacyBrowser()
1110 getString(R.string.app_theme_key) -> {
1111 // Get the app theme entry number that matches the current app theme.
1112 val appThemeEntryNumber: Int = when (sharedPreferences.getString(getString(R.string.app_theme_key), getString(R.string.app_theme_default_value))) {
1113 appThemeEntryValuesStringArray[1] -> 1 // The light theme is selected.
1114 appThemeEntryValuesStringArray[2] -> 2 // The dark theme is selected.
1115 else -> 0 // The system default theme is selected.
1118 // Update the system according to the new theme.
1119 when (appThemeEntryNumber) {
1120 0 -> { // The system default theme is selected.
1121 // Update the theme preference summary text.
1122 appThemePreference.summary = appThemeEntriesStringArray[0]
1124 // Apply the new theme.
1125 if (Build.VERSION.SDK_INT >= 28) { // The system default theme is supported.
1126 // Follow the system default theme.
1127 AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
1128 } else { // The system default theme is not supported.
1129 // Follow the battery saver mode.
1130 AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_AUTO_BATTERY)
1134 1 -> { // The light theme is selected.
1135 // Update the theme preference summary text.
1136 appThemePreference.summary = appThemeEntriesStringArray[1]
1138 // Apply the new theme.
1139 AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
1142 2 -> { // The dark theme is selected.
1143 // Update the theme preference summary text.
1144 appThemePreference.summary = appThemeEntriesStringArray[2]
1146 // Apply the new theme.
1147 AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
1151 // Enable the WebView theme preference if the app theme is not set to light. Google does not allow light themes to display dark WebViews.
1152 webViewThemePreference.isEnabled = (appThemeEntryNumber != 1)
1154 // Get the webView theme entry number that matches the new WebView theme.
1155 val webViewThemeEntryNumber: Int = when (sharedPreferences.getString(getString(R.string.webview_theme_key), getString(R.string.webview_theme_default_value))) {
1156 webViewThemeEntriesStringArray[1] -> 1 // The light theme is selected.
1157 webViewThemeEntryValuesStringArray[2] -> 2 // The dark theme is selected.
1158 else -> 0 // The system default theme is selected.
1161 // Update the WebView theme icon.
1162 if (webViewThemePreference.isEnabled) { // The WebView theme preference is enabled.
1163 when (webViewThemeEntryNumber) {
1164 // The system default WebView theme is selected.
1166 // Get the current theme status.
1167 val currentThemeStatus = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
1169 // Set the icon according to the app theme.
1170 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO)
1171 webViewThemePreference.setIcon(R.drawable.webview_light_theme)
1173 webViewThemePreference.setIcon(R.drawable.webview_dark_theme)
1176 // The light WebView theme is selected.
1179 webViewThemePreference.setIcon(R.drawable.webview_light_theme)
1182 // The dark WebView theme is selected.
1185 webViewThemePreference.setIcon(R.drawable.webview_dark_theme)
1188 } else { // The WebView theme preference is disabled.
1189 webViewThemePreference.setIcon(R.drawable.webview_theme_ghosted)
1193 getString(R.string.webview_theme_key) -> {
1194 // Get the webView theme entry number that matches the new WebView theme.
1195 val newWebViewThemeEntryNumber: Int = when (sharedPreferences.getString(getString(R.string.webview_theme_key), getString(R.string.webview_theme_default_value))) {
1196 webViewThemeEntriesStringArray[1] -> 1 // The light theme is selected.
1197 webViewThemeEntryValuesStringArray[2] -> 2 // The dark theme is selected.
1198 else -> 0 // The system default theme is selected.
1201 // Update the WebView theme icon.
1202 when (newWebViewThemeEntryNumber) {
1203 // The system default WebView theme is selected.
1205 // Get the current theme status.
1206 val currentThemeStatus = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
1209 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO)
1210 webViewThemePreference.setIcon(R.drawable.webview_light_theme)
1212 webViewThemePreference.setIcon(R.drawable.webview_dark_theme)
1215 // The light WebView theme is selected.
1218 webViewThemePreference.setIcon(R.drawable.webview_light_theme)
1221 // The dark WebView theme is selected.
1224 webViewThemePreference.setIcon(R.drawable.webview_dark_theme)
1228 // Set the current theme as the summary text for the preference.
1229 webViewThemePreference.summary = webViewThemeEntriesStringArray[newWebViewThemeEntryNumber]
1232 getString(R.string.wide_viewport_key) -> {
1234 if (sharedPreferences.getBoolean(getString(R.string.wide_viewport_key), true))
1235 wideViewportPreference.setIcon(R.drawable.wide_viewport_enabled)
1237 wideViewportPreference.setIcon(R.drawable.wide_viewport_disabled)
1240 getString(R.string.display_webpage_images_key) -> {
1242 if (sharedPreferences.getBoolean(getString(R.string.display_webpage_images_key), true))
1243 displayWebpageImagesPreference.setIcon(R.drawable.images_enabled)
1245 displayWebpageImagesPreference.setIcon(R.drawable.images_disabled)
1251 private fun restartPrivacyBrowser() {
1252 // Create an intent to restart Privacy Browser.
1253 val restartIntent = requireActivity().parentActivityIntent!!
1255 // `Intent.FLAG_ACTIVITY_CLEAR_TASK` removes all activities from the stack. It requires `Intent.FLAG_ACTIVITY_NEW_TASK`.
1256 restartIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
1258 // Create a handler to restart the activity.
1259 val restartHandler = Handler(Looper.getMainLooper())
1261 // Create a runnable to restart the activity.
1262 val restartRunnable = Runnable {
1263 // Restart the activity.
1264 startActivity(restartIntent)
1266 // Kill this instance of Privacy Browser. Otherwise, the app exhibits sporadic behavior after the restart.
1270 // Restart the activity after 400 milliseconds, so that the app has enough time to save the change to the preference.
1271 restartHandler.postDelayed(restartRunnable, 400)