]> gitweb.stoutner.com Git - PrivacyBrowserAndroid.git/blob - app/src/main/java/com/stoutner/privacybrowser/fragments/SettingsFragment.kt
c6fb15fbba6df558f07d8b73a3034e22384ad894
[PrivacyBrowserAndroid.git] / app / src / main / java / com / stoutner / privacybrowser / fragments / SettingsFragment.kt
1 /*
2  * Copyright 2016-2022 Soren Stoutner <soren@stoutner.com>.
3  *
4  * This file is part of Privacy Browser Android <https://www.stoutner.com/privacy-browser-android>.
5  *
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.
10  *
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.
15  *
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/>.
18  */
19
20 package com.stoutner.privacybrowser.fragments
21
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
33
34 import androidx.appcompat.app.AppCompatDelegate
35 import androidx.preference.Preference
36 import androidx.preference.PreferenceCategory
37 import androidx.preference.PreferenceFragmentCompat
38
39 import com.stoutner.privacybrowser.R
40 import com.stoutner.privacybrowser.activities.MainWebViewActivity
41 import com.stoutner.privacybrowser.helpers.ProxyHelper
42 import kotlin.system.exitProcess
43
44 class SettingsFragment : PreferenceFragmentCompat() {
45     // Declare the class variables.
46     private lateinit var appThemeEntriesStringArray: Array<String>
47     private lateinit var appThemeEntryValuesStringArray: Array<String>
48     private lateinit var defaultUserAgent: String
49     private lateinit var sharedPreferenceChangeListener: OnSharedPreferenceChangeListener
50     private lateinit var translatedUserAgentNamesArray: Array<String>
51     private lateinit var userAgentDataArray: Array<String>
52     private lateinit var userAgentNamesArray: ArrayAdapter<CharSequence>
53     private lateinit var webViewThemeEntriesStringArray: Array<String>
54     private lateinit var webViewThemeEntryValuesStringArray: Array<String>
55
56     // Define the the class views.
57     private lateinit var javaScriptPreference: Preference
58     private lateinit var cookiesPreference: Preference
59     private lateinit var domStoragePreference: Preference
60     private lateinit var formDataPreference: Preference  // The form data preference can be removed once the minimum API >= 26.
61     private lateinit var userAgentPreference: Preference
62     private lateinit var customUserAgentPreference: Preference
63     private lateinit var xRequestedWithHeaderPreference: Preference
64     private lateinit var incognitoModePreference: Preference
65     private lateinit var allowScreenshotsPreference: Preference
66     private lateinit var easyListPreference: Preference
67     private lateinit var easyPrivacyPreference: Preference
68     private lateinit var fanboyAnnoyanceListPreference: Preference
69     private lateinit var fanboySocialBlockingListPreference: Preference
70     private lateinit var ultraListPreference: Preference
71     private lateinit var ultraPrivacyPreference: Preference
72     private lateinit var blockAllThirdPartyRequestsPreference: Preference
73     private lateinit var trackingQueriesPreference: Preference
74     private lateinit var ampRedirectsPreference: Preference
75     private lateinit var searchPreference: Preference
76     private lateinit var searchCustomURLPreference: Preference
77     private lateinit var proxyPreference: Preference
78     private lateinit var proxyCustomUrlPreference: Preference
79     private lateinit var fullScreenBrowsingModePreference: Preference
80     private lateinit var hideAppBarPreference: Preference
81     private lateinit var clearEverythingPreference: Preference
82     private lateinit var clearCookiesPreference: Preference
83     private lateinit var clearDomStoragePreference: Preference
84     private lateinit var clearFormDataPreference: Preference  // The clear form data preference can be removed once the minimum API >= 26.
85     private lateinit var clearLogcatPreference: Preference
86     private lateinit var clearCachePreference: Preference
87     private lateinit var homepagePreference: Preference
88     private lateinit var fontSizePreference: Preference
89     private lateinit var openIntentsInNewTabPreference: Preference
90     private lateinit var swipeToRefreshPreference: Preference
91     private lateinit var downloadWithExternalAppPreference: Preference
92     private lateinit var scrollAppBarPreference: Preference
93     private lateinit var bottomAppBarPreference: Preference
94     private lateinit var displayAdditionalAppBarIconsPreference: Preference
95     private lateinit var appThemePreference: Preference
96     private lateinit var webViewThemePreference: Preference
97     private lateinit var wideViewportPreference: Preference
98     private lateinit var displayWebpageImagesPreference: Preference
99
100     override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
101         // Load the preferences from the XML file.
102         setPreferencesFromResource(R.xml.preferences, rootKey)
103
104         // Get a handle for the shared preferences.
105         val sharedPreferences = preferenceScreen.sharedPreferences!!
106
107         // Get handles for the preferences.
108         javaScriptPreference = findPreference(getString(R.string.javascript_key))!!
109         cookiesPreference = findPreference(getString(R.string.cookies_key))!!
110         domStoragePreference = findPreference(getString(R.string.dom_storage_key))!!
111         formDataPreference = findPreference(getString(R.string.save_form_data_key))!!  // The form data preference can be removed once the minimum API >= 26.
112         userAgentPreference = findPreference(getString(R.string.user_agent_key))!!
113         customUserAgentPreference = findPreference(getString(R.string.custom_user_agent_key))!!
114         xRequestedWithHeaderPreference = findPreference(getString(R.string.x_requested_with_header_key))!!
115         incognitoModePreference = findPreference(getString(R.string.incognito_mode_key))!!
116         allowScreenshotsPreference = findPreference(getString(R.string.allow_screenshots_key))!!
117         easyListPreference = findPreference(getString(R.string.easylist_key))!!
118         easyPrivacyPreference = findPreference(getString(R.string.easyprivacy_key))!!
119         fanboyAnnoyanceListPreference = findPreference(getString(R.string.fanboys_annoyance_list_key))!!
120         fanboySocialBlockingListPreference = findPreference(getString(R.string.fanboys_social_blocking_list_key))!!
121         ultraListPreference = findPreference(getString(R.string.ultralist_key))!!
122         ultraPrivacyPreference = findPreference(getString(R.string.ultraprivacy_key))!!
123         blockAllThirdPartyRequestsPreference = findPreference(getString(R.string.block_all_third_party_requests_key))!!
124         trackingQueriesPreference = findPreference(getString(R.string.tracking_queries_key))!!
125         ampRedirectsPreference = findPreference(getString(R.string.amp_redirects_key))!!
126         searchPreference = findPreference(getString(R.string.search_key))!!
127         searchCustomURLPreference = findPreference(getString(R.string.search_custom_url_key))!!
128         proxyPreference = findPreference(getString(R.string.proxy_key))!!
129         proxyCustomUrlPreference = findPreference(getString(R.string.proxy_custom_url_key))!!
130         fullScreenBrowsingModePreference = findPreference(getString(R.string.full_screen_browsing_mode_key))!!
131         hideAppBarPreference = findPreference(getString(R.string.hide_app_bar_key))!!
132         clearEverythingPreference = findPreference(getString(R.string.clear_everything_key))!!
133         clearCookiesPreference = findPreference(getString(R.string.clear_cookies_key))!!
134         clearDomStoragePreference = findPreference(getString(R.string.clear_dom_storage_key))!!
135         clearFormDataPreference = findPreference(getString(R.string.clear_form_data_key))!!  // The clear form data preference can be removed once the minimum API >= 26.
136         clearLogcatPreference = findPreference(getString(R.string.clear_logcat_key))!!
137         clearCachePreference = findPreference(getString(R.string.clear_cache_key))!!
138         homepagePreference = findPreference(getString(R.string.homepage_key))!!
139         fontSizePreference = findPreference(getString(R.string.font_size_key))!!
140         openIntentsInNewTabPreference = findPreference(getString(R.string.open_intents_in_new_tab_key))!!
141         swipeToRefreshPreference = findPreference(getString(R.string.swipe_to_refresh_key))!!
142         downloadWithExternalAppPreference = findPreference(getString(R.string.download_with_external_app_key))!!
143         scrollAppBarPreference = findPreference(getString(R.string.scroll_app_bar_key))!!
144         bottomAppBarPreference = findPreference(getString(R.string.bottom_app_bar_key))!!
145         displayAdditionalAppBarIconsPreference = findPreference(getString(R.string.display_additional_app_bar_icons_key))!!
146         appThemePreference = findPreference(getString(R.string.app_theme_key))!!
147         webViewThemePreference = findPreference(getString(R.string.webview_theme_key))!!
148         wideViewportPreference = findPreference(getString(R.string.wide_viewport_key))!!
149         displayWebpageImagesPreference = findPreference(getString(R.string.display_webpage_images_key))!!
150
151         // Set the preference dependencies.
152         domStoragePreference.dependency = getString(R.string.javascript_key)
153         hideAppBarPreference.dependency = getString(R.string.full_screen_browsing_mode_key)
154
155         // Get strings from the preferences.
156         val userAgentName = sharedPreferences.getString(getString(R.string.user_agent_key), getString(R.string.user_agent_default_value))
157         val searchString = sharedPreferences.getString(getString(R.string.search_key), getString(R.string.search_default_value))
158         val proxyString = sharedPreferences.getString(getString(R.string.proxy_key), getString(R.string.proxy_default_value))
159
160         // Get booleans that are used in multiple places from the preferences.
161         val javaScriptEnabled = sharedPreferences.getBoolean(getString(R.string.javascript_key), false)
162         val fanboyAnnoyanceListEnabled = sharedPreferences.getBoolean(getString(R.string.fanboys_annoyance_list_key), true)
163         val fanboySocialBlockingEnabled = sharedPreferences.getBoolean(getString(R.string.fanboys_social_blocking_list_key), true)
164         val fullScreenBrowsingMode = sharedPreferences.getBoolean(getString(R.string.full_screen_browsing_mode_key), false)
165         val clearEverything = sharedPreferences.getBoolean(getString(R.string.clear_everything_key), true)
166
167         // Remove the form data preferences if the API is >= 26 as they no longer do anything.
168         if (Build.VERSION.SDK_INT >= 26) {
169             // Get handles for the categories.
170             val privacyCategory = findPreference<PreferenceCategory>(getString(R.string.privacy_category_key))!!
171             val clearAndExitCategory = findPreference<PreferenceCategory>(getString(R.string.clear_and_exit_category_key))!!
172
173             // Remove the form data preferences.
174             privacyCategory.removePreference(formDataPreference)
175             clearAndExitCategory.removePreference(clearFormDataPreference)
176         }
177
178         // Only enable Fanboy's social blocking list preference if Fanboy's annoyance list is disabled.
179         fanboySocialBlockingListPreference.isEnabled = !fanboyAnnoyanceListEnabled
180
181
182         // Inflate a WebView to get the default user agent.
183         val inflater = requireActivity().layoutInflater
184
185         // `@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.
186         @SuppressLint("InflateParams") val bareWebViewLayout = inflater.inflate(R.layout.bare_webview, null, false)
187
188         // Get a handle for the bare WebView.
189         val bareWebView = bareWebViewLayout.findViewById<WebView>(R.id.bare_webview)
190
191         // Get the default user agent.
192         defaultUserAgent = bareWebView.settings.userAgentString
193
194         // Get the user agent arrays.
195         userAgentNamesArray = ArrayAdapter.createFromResource(requireContext(), R.array.user_agent_names, R.layout.spinner_item)
196         translatedUserAgentNamesArray = resources.getStringArray(R.array.translated_user_agent_names)
197         userAgentDataArray = resources.getStringArray(R.array.user_agent_data)
198
199         // Populate the user agent summary.
200         when (val userAgentArrayPosition = userAgentNamesArray.getPosition(userAgentName)) {
201             // The user agent name is not on the canonical list.
202             // 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.
203             MainWebViewActivity.UNRECOGNIZED_USER_AGENT -> userAgentPreference.summary = userAgentName
204
205             // Get the user agent text from the webview (which changes based on the version of Android and WebView installed).
206             MainWebViewActivity.SETTINGS_WEBVIEW_DEFAULT_USER_AGENT -> userAgentPreference.summary = "${translatedUserAgentNamesArray[userAgentArrayPosition]}:\n$defaultUserAgent"
207
208             // Display the custom user agent.
209             MainWebViewActivity.SETTINGS_CUSTOM_USER_AGENT -> userAgentPreference.setSummary(R.string.custom_user_agent)
210
211             // Get the user agent summary from the user agent data array.
212             else -> userAgentPreference.summary = "${translatedUserAgentNamesArray[userAgentArrayPosition]}:\n${userAgentDataArray[userAgentArrayPosition]}"
213         }
214
215         // Set the summary text for the custom user agent preference.
216         customUserAgentPreference.summary = sharedPreferences.getString(getString(R.string.custom_user_agent_key), getString(R.string.custom_user_agent_default_value))
217
218         // Only enable the custom user agent preference if the user agent is set to custom.
219         customUserAgentPreference.isEnabled = (userAgentPreference.summary == getString(R.string.custom_user_agent))
220
221         // Set the search URL as the summary text for the search preference when the preference screen is loaded.
222         if (searchString == getString(R.string.custom_url_item)) {
223             // Use R.string.custom_url, which will be translated, instead of the array value, which will not.
224             searchPreference.setSummary(R.string.custom_url)
225         } else {
226             // Set the array value as the summary text.
227             searchPreference.summary = searchString
228         }
229
230         // Set the summary text for the search custom URL (the default is `""`).
231         searchCustomURLPreference.summary = sharedPreferences.getString(getString(R.string.search_custom_url_key), getString(R.string.search_custom_url_default_value))
232
233         // Only enable the search custom URL preference if the search is set to a custom URL.
234         searchCustomURLPreference.isEnabled = (searchString == getString(R.string.custom_url_item))
235
236         // Set the summary text for the proxy preference.
237         proxyPreference.summary = when (proxyString) {
238             ProxyHelper.NONE -> getString(R.string.no_proxy_enabled)
239             ProxyHelper.TOR -> getString(R.string.tor_enabled)
240             ProxyHelper.I2P -> getString(R.string.i2p_enabled)
241             ProxyHelper.CUSTOM -> getString(R.string.custom_proxy)
242             else -> getString(R.string.no_proxy_enabled)
243         }
244
245         // Set the summary text for the custom proxy URL.
246         proxyCustomUrlPreference.summary = sharedPreferences.getString(getString(R.string.proxy_custom_url_key), getString(R.string.proxy_custom_url_default_value))
247
248         // Only enable the custom proxy URL if a custom proxy is selected.
249         proxyCustomUrlPreference.isEnabled = proxyString == ProxyHelper.CUSTOM
250
251         // Set the status of the clear and exit preferences.
252         clearCookiesPreference.isEnabled = !clearEverything
253         clearDomStoragePreference.isEnabled = !clearEverything
254         clearFormDataPreference.isEnabled = !clearEverything  // Clear form data can be removed once the minimum API is >= 26.
255         clearLogcatPreference.isEnabled = !clearEverything
256         clearCachePreference.isEnabled = !clearEverything
257
258         // Set the homepage URL as the summary text for the homepage preference.
259         homepagePreference.summary = sharedPreferences.getString(getString(R.string.homepage_key), getString(R.string.homepage_default_value))
260
261         // Set the font size as the summary text for the preference.
262         fontSizePreference.summary = sharedPreferences.getString(getString(R.string.font_size_key), getString(R.string.font_size_default_value)) + "%"
263
264         // Get the app theme string arrays.
265         appThemeEntriesStringArray = resources.getStringArray(R.array.app_theme_entries)
266         appThemeEntryValuesStringArray = resources.getStringArray(R.array.app_theme_entry_values)
267
268         // Get the app theme entry number that matches the current app theme.
269         val appThemeEntryNumber: Int = when (sharedPreferences.getString(getString(R.string.app_theme_key), getString(R.string.app_theme_default_value))) {
270             appThemeEntryValuesStringArray[1] -> 1  // The light theme is selected.
271             appThemeEntryValuesStringArray[2] -> 2  // The dark theme is selected.
272             else -> 0  // The system default theme is selected.
273         }
274
275         // Set the current theme as the summary text for the preference.
276         appThemePreference.summary = appThemeEntriesStringArray[appThemeEntryNumber]
277
278         // Enable the WebView theme preference if the API < 33 or the app theme is not set to light.  Google no longer allows light themes to display dark WebViews.
279         webViewThemePreference.isEnabled = ((Build.VERSION.SDK_INT < 33) || (appThemeEntryNumber != 1))
280
281         // Get the WebView theme string arrays.
282         webViewThemeEntriesStringArray = resources.getStringArray(R.array.webview_theme_entries)
283         webViewThemeEntryValuesStringArray = resources.getStringArray(R.array.webview_theme_entry_values)
284
285         // Get the WebView theme entry number that matches the current WebView theme.
286         val webViewThemeEntryNumber: Int = when (sharedPreferences.getString(getString(R.string.webview_theme_key), getString(R.string.webview_theme_default_value))) {
287             webViewThemeEntryValuesStringArray[1] -> 1  // The light theme is selected.
288             webViewThemeEntryValuesStringArray[2] -> 2  // The dark theme is selected.
289             else -> 0  // The system default theme is selected.
290         }
291
292         // Set the current theme as the summary text for the preference.
293         webViewThemePreference.summary = webViewThemeEntriesStringArray[webViewThemeEntryNumber]
294
295         // Set the JavaScript icon.
296         if (javaScriptEnabled)
297             javaScriptPreference.setIcon(R.drawable.javascript_enabled)
298         else
299             javaScriptPreference.setIcon(R.drawable.privacy_mode)
300
301         // Set the cookies icon.
302         if (sharedPreferences.getBoolean(getString(R.string.cookies_key), false))
303             cookiesPreference.setIcon(R.drawable.cookies_enabled)
304         else
305             cookiesPreference.setIcon(R.drawable.cookies_disabled)
306
307         // Set the DOM storage icon.
308         if (javaScriptEnabled) {  // JavaScript is enabled.
309             if (sharedPreferences.getBoolean(getString(R.string.dom_storage_key), false))  // DOM storage is enabled.
310                 domStoragePreference.setIcon(R.drawable.dom_storage_enabled)
311             else  // DOM storage is disabled.
312                 domStoragePreference.setIcon(R.drawable.dom_storage_disabled)
313         } else {  // JavaScript is disabled.  DOM storage should be ghosted.
314             domStoragePreference.setIcon(R.drawable.dom_storage_ghosted)
315         }
316
317         // Set the save form data icon if API < 26.  Save form data has no effect on API >= 26.
318         if (Build.VERSION.SDK_INT < 26) {
319             if (sharedPreferences.getBoolean(getString(R.string.save_form_data_key), false))
320                 formDataPreference.setIcon(R.drawable.form_data_enabled)
321             else
322                 formDataPreference.setIcon(R.drawable.form_data_disabled)
323         }
324
325         // Set the custom user agent icon.
326         if (customUserAgentPreference.isEnabled)
327             customUserAgentPreference.setIcon(R.drawable.custom_user_agent_enabled)
328         else
329             customUserAgentPreference.setIcon(R.drawable.custom_user_agent_ghosted)
330
331         // Set the X-Requested With header icon.
332         if (sharedPreferences.getBoolean(getString(R.string.x_requested_with_header_key), true))
333             xRequestedWithHeaderPreference.setIcon(R.drawable.x_requested_with_header_enabled)
334         else
335             xRequestedWithHeaderPreference.setIcon(R.drawable.x_requested_with_header_disabled)
336
337         // Set the incognito mode icon.
338         if (sharedPreferences.getBoolean(getString(R.string.incognito_mode_key), false))
339             incognitoModePreference.setIcon(R.drawable.incognito_mode_enabled)
340         else
341             incognitoModePreference.setIcon(R.drawable.incognito_mode_disabled)
342
343         // Set the allow screenshots icon.
344         if (sharedPreferences.getBoolean(getString(R.string.allow_screenshots_key), false))
345             allowScreenshotsPreference.setIcon(R.drawable.allow_screenshots_enabled)
346         else
347             allowScreenshotsPreference.setIcon(R.drawable.allow_screenshots_disabled)
348
349         // Set the EasyList icon.
350         if (sharedPreferences.getBoolean(getString(R.string.easylist_key), true))
351             easyListPreference.setIcon(R.drawable.block_ads_enabled)
352         else
353             easyListPreference.setIcon(R.drawable.block_ads_disabled)
354
355         // Set the EasyPrivacy icon.
356         if (sharedPreferences.getBoolean(getString(R.string.easyprivacy_key), true))
357             easyPrivacyPreference.setIcon(R.drawable.block_tracking_enabled)
358         else
359             easyPrivacyPreference.setIcon(R.drawable.block_tracking_disabled)
360
361         // Set the Fanboy lists icons.
362         if (fanboyAnnoyanceListEnabled) {
363             // Set the Fanboy annoyance list icon.
364             fanboyAnnoyanceListPreference.setIcon(R.drawable.social_media_enabled)
365
366             // Set the Fanboy social blocking list icon.
367             fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_ghosted)
368         } else {
369             // Set the Fanboy annoyance list icon.
370             fanboyAnnoyanceListPreference.setIcon(R.drawable.social_media_disabled)
371
372             // Set the Fanboy social blocking list icon.
373             if (fanboySocialBlockingEnabled)
374                 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_enabled)
375             else
376                 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_disabled)
377         }
378
379         // Set the UltraList icon.
380         if (sharedPreferences.getBoolean(getString(R.string.ultralist_key), true))
381             ultraListPreference.setIcon(R.drawable.block_ads_enabled)
382         else
383             ultraListPreference.setIcon(R.drawable.block_ads_disabled)
384
385         // Set the UltraPrivacy icon.
386         if (sharedPreferences.getBoolean(getString(R.string.ultraprivacy_key), true))
387             ultraPrivacyPreference.setIcon(R.drawable.block_tracking_enabled)
388         else
389             ultraPrivacyPreference.setIcon(R.drawable.block_tracking_disabled)
390
391         // Set the block all third-party requests icon.
392         if (sharedPreferences.getBoolean(getString(R.string.block_all_third_party_requests), false))
393             blockAllThirdPartyRequestsPreference.setIcon(R.drawable.block_all_third_party_requests_enabled)
394         else
395             blockAllThirdPartyRequestsPreference.setIcon(R.drawable.block_all_third_party_requests_disabled)
396
397         // Set the Tracking Queries icon.
398         if (sharedPreferences.getBoolean(getString(R.string.tracking_queries_key), true))
399             trackingQueriesPreference.setIcon(R.drawable.modify_url_enabled)
400         else
401             trackingQueriesPreference.setIcon(R.drawable.modify_url_disabled)
402
403         // Set the AMP Redirects icon.
404         if (sharedPreferences.getBoolean(getString(R.string.amp_redirects_key), true))
405             ampRedirectsPreference.setIcon(R.drawable.modify_url_enabled)
406         else
407             ampRedirectsPreference.setIcon(R.drawable.modify_url_disabled)
408
409         // Set the search custom URL icon.
410         if (searchCustomURLPreference.isEnabled)
411             searchCustomURLPreference.setIcon(R.drawable.search_custom_enabled)
412         else
413             searchCustomURLPreference.setIcon(R.drawable.search_custom_ghosted)
414
415         // Set the proxy icons according to the theme and status.
416         if (proxyString == ProxyHelper.NONE) {  // Proxying is disabled.
417             // Set the main proxy icon to be disabled.
418             proxyPreference.setIcon(R.drawable.proxy_disabled)
419
420             // Set the custom proxy URL icon to be ghosted.
421             proxyCustomUrlPreference.setIcon(R.drawable.proxy_ghosted)
422         } else {  // Proxying is enabled.
423             // Set the main proxy icon to be enabled.
424             proxyPreference.setIcon(R.drawable.proxy_enabled)
425
426             // Set the custom proxy URL icon according to its status.
427             if (proxyCustomUrlPreference.isEnabled)
428                 proxyCustomUrlPreference.setIcon(R.drawable.proxy_enabled)
429             else
430                 proxyCustomUrlPreference.setIcon(R.drawable.proxy_ghosted)
431         }
432
433         // Set the full-screen browsing mode icons.
434         if (fullScreenBrowsingMode) {  // Full-screen browsing mode is enabled.
435             // Set the full screen browsing mode preference icon.
436             fullScreenBrowsingModePreference.setIcon(R.drawable.full_screen_enabled)
437
438             // Set the hide app bar icon.
439             if (sharedPreferences.getBoolean(getString(R.string.hide_app_bar_key), true))
440                 hideAppBarPreference.setIcon(R.drawable.app_bar_enabled)
441             else
442                 hideAppBarPreference.setIcon(R.drawable.app_bar_disabled)
443         } else {  // Full screen browsing mode is disabled.
444             // Set the icons.
445             fullScreenBrowsingModePreference.setIcon(R.drawable.full_screen_disabled)
446             hideAppBarPreference.setIcon(R.drawable.app_bar_ghosted)
447         }
448
449         // Set the clear everything icon.
450         if (clearEverything) {
451             clearEverythingPreference.setIcon(R.drawable.clear_everything_enabled)
452         } else {
453             clearEverythingPreference.setIcon(R.drawable.clear_everything_disabled)
454         }
455
456         // Set the clear cookies icon.
457         if (clearEverything || sharedPreferences.getBoolean(getString(R.string.clear_cookies_key), true))
458             clearCookiesPreference.setIcon(R.drawable.clear_cookies_enabled)
459         else
460             clearCookiesPreference.setIcon(R.drawable.clear_cookies_disabled)
461
462         // Set the clear DOM storage icon.
463         if (clearEverything || sharedPreferences.getBoolean(getString(R.string.clear_dom_storage_key), true))
464             clearDomStoragePreference.setIcon(R.drawable.clear_dom_storage_enabled)
465         else
466             clearDomStoragePreference.setIcon(R.drawable.clear_dom_storage_disabled)
467
468         // Set the clear form data icon if the API < 26.  It has no effect on newer versions of Android.
469         if (Build.VERSION.SDK_INT < 26) {
470             if (clearEverything || sharedPreferences.getBoolean(getString(R.string.clear_form_data_key), true))
471                 clearFormDataPreference.setIcon(R.drawable.clear_form_data_enabled)
472             else
473                 clearFormDataPreference.setIcon(R.drawable.clear_form_data_disabled)
474         }
475
476         // Set the clear logcat icon.
477         if (clearEverything || sharedPreferences.getBoolean(getString(R.string.clear_logcat_key), true))
478             clearLogcatPreference.setIcon(R.drawable.clear_logcat_enabled)
479         else
480             clearLogcatPreference.setIcon(R.drawable.clear_logcat_disabled)
481
482         // Set the clear cache icon.
483         if (clearEverything || sharedPreferences.getBoolean(getString(R.string.clear_cache_key), true))
484             clearCachePreference.setIcon(R.drawable.clear_cache_enabled)
485         else
486             clearCachePreference.setIcon(R.drawable.clear_cache_disabled)
487
488         // Set the open intents in new tab icon.
489         if (sharedPreferences.getBoolean(getString(R.string.open_intents_in_new_tab_key), true))
490             openIntentsInNewTabPreference.setIcon(R.drawable.tab_enabled)
491         else
492             openIntentsInNewTabPreference.setIcon(R.drawable.tab_disabled)
493
494         // Set the swipe to refresh icon.
495         if (sharedPreferences.getBoolean(getString(R.string.swipe_to_refresh_key), true))
496             swipeToRefreshPreference.setIcon(R.drawable.refresh_enabled)
497         else
498             swipeToRefreshPreference.setIcon(R.drawable.refresh_disabled)
499
500         // Set the download with external app icon.
501         if (sharedPreferences.getBoolean(getString(R.string.download_with_external_app_key), false))
502             downloadWithExternalAppPreference.setIcon(R.drawable.download_with_external_app_enabled)
503         else
504             downloadWithExternalAppPreference.setIcon(R.drawable.download_with_external_app_disabled)
505
506         // Set the scroll app bar icon.
507         if (sharedPreferences.getBoolean(getString(R.string.scroll_app_bar_key), true))
508             scrollAppBarPreference.setIcon(R.drawable.app_bar_enabled)
509         else
510             scrollAppBarPreference.setIcon(R.drawable.app_bar_disabled)
511
512         // Set the bottom app bar icon.
513         if (sharedPreferences.getBoolean(getString(R.string.bottom_app_bar_key), false))
514             bottomAppBarPreference.setIcon(R.drawable.bottom_app_bar_enabled)
515         else
516             bottomAppBarPreference.setIcon(R.drawable.bottom_app_bar_disabled)
517
518         // Set the display additional app bar icons icon.
519         if (sharedPreferences.getBoolean(getString(R.string.display_additional_app_bar_icons_key), false))
520             displayAdditionalAppBarIconsPreference.setIcon(R.drawable.more_enabled)
521         else
522             displayAdditionalAppBarIconsPreference.setIcon(R.drawable.more_disabled)
523
524         // Set the WebView theme icon.
525         if (webViewThemePreference.isEnabled) {  // The WebView theme preference is enabled.
526             when (webViewThemeEntryNumber) {
527                 // The system default WebView theme is selected.
528                 0 -> {
529                     // Get the current theme status.
530                     val currentThemeStatus = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
531
532                     // Set the icon according to the app theme.
533                     if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO)
534                         webViewThemePreference.setIcon(R.drawable.webview_light_theme)
535                     else
536                         webViewThemePreference.setIcon(R.drawable.webview_dark_theme)
537                 }
538
539                 // The light WebView theme is selected.
540                 1 -> {
541                     // Set the icon.
542                     webViewThemePreference.setIcon(R.drawable.webview_light_theme)
543                 }
544
545                 // The dark WebView theme is selected.
546                 2 -> {
547                     // Set the icon.
548                     webViewThemePreference.setIcon(R.drawable.webview_dark_theme)
549                 }
550             }
551         } else {  // The WebView theme preference is disabled.
552             webViewThemePreference.setIcon(R.drawable.webview_theme_ghosted)
553         }
554
555         // Set the wide viewport icon.
556         if (sharedPreferences.getBoolean(getString(R.string.wide_viewport_key), true))
557             wideViewportPreference.setIcon(R.drawable.wide_viewport_enabled)
558         else
559             wideViewportPreference.setIcon(R.drawable.wide_viewport_disabled)
560
561         // Set the display webpage images icon.
562         if (sharedPreferences.getBoolean(getString(R.string.display_webpage_images_key), true))
563             displayWebpageImagesPreference.setIcon(R.drawable.images_enabled)
564         else
565             displayWebpageImagesPreference.setIcon(R.drawable.images_disabled)
566     }
567
568     // The listener should be unregistered when the app is paused.
569     override fun onPause() {
570         // Run the default commands.
571         super.onPause()
572
573         // Get a handle for the shared preferences.
574         val sharedPreferences = preferenceScreen.sharedPreferences!!
575
576         // Unregister the shared preference listener.
577         sharedPreferences.unregisterOnSharedPreferenceChangeListener(sharedPreferenceChangeListener)
578     }
579
580     // The listener should be re-registered when the app is resumed.
581     override fun onResume() {
582         // Run the default commands.
583         super.onResume()
584
585         // Get a new shared preference change listener.
586         sharedPreferenceChangeListener = getSharedPreferenceChangeListener()
587
588         // Get a handle for the shared preferences.
589         val sharedPreferences = preferenceScreen.sharedPreferences!!
590
591         // Re-register the shared preference listener.
592         sharedPreferences.registerOnSharedPreferenceChangeListener(sharedPreferenceChangeListener)
593     }
594
595     private fun getSharedPreferenceChangeListener(): OnSharedPreferenceChangeListener {
596         // Return the shared preference change listener.
597         return OnSharedPreferenceChangeListener { sharedPreferences: SharedPreferences, key: String? ->
598             when (key) {
599                 getString(R.string.javascript_key) -> {
600                     // Update the icons and the DOM storage preference status.
601                     if (sharedPreferences.getBoolean(getString(R.string.javascript_key), false)) {  // The JavaScript preference is enabled.
602                         // Update the icon for the JavaScript preference.
603                         javaScriptPreference.setIcon(R.drawable.javascript_enabled)
604
605                         // Update the status of the DOM storage preference.
606                         domStoragePreference.isEnabled = true
607
608                         // Update the icon for the DOM storage preference.
609                         if (sharedPreferences.getBoolean(getString(R.string.dom_storage_key), false))
610                             domStoragePreference.setIcon(R.drawable.dom_storage_enabled)
611                         else
612                             domStoragePreference.setIcon(R.drawable.dom_storage_disabled)
613                     } else {  // The JavaScript preference is disabled.
614                         // Update the icon for the JavaScript preference.
615                         javaScriptPreference.setIcon(R.drawable.privacy_mode)
616
617                         // Update the status of the DOM storage preference.
618                         domStoragePreference.isEnabled = false
619
620                         // Set the icon for DOM storage preference to be ghosted.
621                         domStoragePreference.setIcon(R.drawable.dom_storage_ghosted)
622                     }
623                 }
624
625                 getString(R.string.cookies_key) -> {
626                     // Update the icon.
627                     if (sharedPreferences.getBoolean(getString(R.string.cookies_key), false))
628                         cookiesPreference.setIcon(R.drawable.cookies_enabled)
629                     else
630                         cookiesPreference.setIcon(R.drawable.cookies_disabled)
631                 }
632
633                 getString(R.string.dom_storage_key) -> {
634                     // Update the icon.
635                     if (sharedPreferences.getBoolean(getString(R.string.dom_storage_key), false))
636                         domStoragePreference.setIcon(R.drawable.dom_storage_enabled)
637                     else
638                         domStoragePreference.setIcon(R.drawable.dom_storage_disabled)
639                 }
640
641                 getString(R.string.save_form_data_key) -> {  // Saved form data can be removed once the minimum API >= 26.
642                     // Update the icon.
643                     if (sharedPreferences.getBoolean(getString(R.string.save_form_data_key), false))
644                         formDataPreference.setIcon(R.drawable.form_data_enabled)
645                     else
646                         formDataPreference.setIcon(R.drawable.form_data_disabled)
647                 }
648
649                 getString(R.string.user_agent_key) -> {
650                     // Get the new user agent name.
651                     val newUserAgentName = sharedPreferences.getString(getString(R.string.user_agent_key), getString(R.string.user_agent_default_value))
652
653                     // Get the array position for the new user agent name.
654                     val newUserAgentArrayPosition = userAgentNamesArray.getPosition(newUserAgentName)
655
656                     // Get the translated new user agent name.
657                     val translatedNewUserAgentName = translatedUserAgentNamesArray[newUserAgentArrayPosition]
658
659                     // Populate the user agent summary.
660                     when (newUserAgentArrayPosition) {
661                         MainWebViewActivity.SETTINGS_WEBVIEW_DEFAULT_USER_AGENT -> {
662                             // Get the user agent text from the webview (which changes based on the version of Android and WebView installed).
663                             userAgentPreference.summary = "$translatedNewUserAgentName:\n$defaultUserAgent"
664
665                             // Disable the custom user agent preference.
666                             customUserAgentPreference.isEnabled = false
667
668                             // Set the custom user agent preference icon.
669                             customUserAgentPreference.setIcon(R.drawable.custom_user_agent_ghosted)
670                         }
671
672                         MainWebViewActivity.SETTINGS_CUSTOM_USER_AGENT -> {
673                             // Set the summary text.
674                             userAgentPreference.setSummary(R.string.custom_user_agent)
675
676                             // Enable the custom user agent preference.
677                             customUserAgentPreference.isEnabled = true
678
679                             // Set the custom user agent preference icon.
680                             customUserAgentPreference.setIcon(R.drawable.custom_user_agent_enabled)
681                         }
682
683                         else -> {
684                             // Get the user agent summary from the user agent data array.
685                             userAgentPreference.summary = "$translatedNewUserAgentName:\n${userAgentDataArray[newUserAgentArrayPosition]}"
686
687                             // Disable the custom user agent preference.
688                             customUserAgentPreference.isEnabled = false
689
690                             // Set the custom user agent preference icon.
691                             customUserAgentPreference.setIcon(R.drawable.custom_user_agent_ghosted)
692                         }
693                     }
694                 }
695
696                 getString(R.string.custom_user_agent_key) -> {
697                     // Set the new custom user agent as the summary text for the preference.
698                     customUserAgentPreference.summary = sharedPreferences.getString(getString(R.string.custom_user_agent_key), getString(R.string.custom_user_agent_default_value))
699                 }
700
701                 getString(R.string.x_requested_with_header_key) -> {
702                     // Update the icon.
703                     if (sharedPreferences.getBoolean(getString(R.string.x_requested_with_header_key), true))
704                         xRequestedWithHeaderPreference.setIcon(R.drawable.x_requested_with_header_enabled)
705                     else
706                         xRequestedWithHeaderPreference.setIcon(R.drawable.x_requested_with_header_disabled)
707
708                     // Restart Privacy Browser.
709                     restartPrivacyBrowser()
710                 }
711
712                 getString(R.string.incognito_mode_key) -> {
713                     // Update the icon.
714                     if (sharedPreferences.getBoolean(getString(R.string.incognito_mode_key), false))
715                         incognitoModePreference.setIcon(R.drawable.incognito_mode_enabled)
716                     else
717                         incognitoModePreference.setIcon(R.drawable.incognito_mode_disabled)
718                 }
719
720                 getString(R.string.allow_screenshots_key) -> {
721                     // Update the icon.
722                     if (sharedPreferences.getBoolean(getString(R.string.allow_screenshots_key), false))
723                         allowScreenshotsPreference.setIcon(R.drawable.allow_screenshots_enabled)
724                     else
725                         allowScreenshotsPreference.setIcon(R.drawable.allow_screenshots_disabled)
726
727                     // Restart Privacy Browser.
728                     restartPrivacyBrowser()
729                 }
730
731                 getString(R.string.easylist_key) -> {
732                     // Update the icon.
733                     if (sharedPreferences.getBoolean(getString(R.string.easylist_key), true))
734                         easyListPreference.setIcon(R.drawable.block_ads_enabled)
735                     else
736                         easyListPreference.setIcon(R.drawable.block_ads_disabled)
737                 }
738
739                 getString(R.string.easyprivacy_key) -> {
740                     // Update the icon.
741                     if (sharedPreferences.getBoolean(getString(R.string.easyprivacy_key), true))
742                         easyPrivacyPreference.setIcon(R.drawable.block_tracking_enabled)
743                     else
744                         easyPrivacyPreference.setIcon(R.drawable.block_tracking_disabled)
745                 }
746
747                 getString(R.string.fanboys_annoyance_list_key) -> {
748                     // Get the current Fanboy settings.
749                     val currentFanboyAnnoyanceList = sharedPreferences.getBoolean(getString(R.string.fanboys_annoyance_list_key), true)
750                     val currentFanboySocialBlockingList = sharedPreferences.getBoolean(getString(R.string.fanboys_social_blocking_list_key), true)
751
752                     // Update the Fanboy icons.
753                     if (currentFanboyAnnoyanceList) {  // Fanboy's annoyance list is enabled.
754                         // Update the Fanboy's annoyance list icon.
755                         fanboyAnnoyanceListPreference.setIcon(R.drawable.social_media_enabled)
756
757                         // Update the Fanboy's social blocking list icon.
758                         fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_ghosted)
759                     } else {  // Fanboy's annoyance list is disabled.
760                         // Update the Fanboy's annoyance list icon.
761                         fanboyAnnoyanceListPreference.setIcon(R.drawable.social_media_disabled)
762
763                         // Update the Fanboy's social blocking list icon.
764                         if (currentFanboySocialBlockingList)
765                             fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_enabled)
766                         else
767                             fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_disabled)
768                     }
769
770                     // Only enable Fanboy's social blocking list preference if Fanboy's annoyance list preference is disabled.
771                     fanboySocialBlockingListPreference.isEnabled = !currentFanboyAnnoyanceList
772                 }
773
774                 getString(R.string.fanboys_social_blocking_list_key) -> {
775                     // Update the icon.
776                     if (sharedPreferences.getBoolean(getString(R.string.fanboys_social_blocking_list_key), true))
777                         fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_enabled)
778                     else
779                         fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_disabled)
780                 }
781
782                 getString(R.string.ultralist_key) -> {
783                     // Update the icon.
784                     if (sharedPreferences.getBoolean(getString(R.string.ultralist_key), true))
785                         ultraListPreference.setIcon(R.drawable.block_ads_enabled)
786                     else
787                         ultraListPreference.setIcon(R.drawable.block_ads_disabled)
788                 }
789
790                 getString(R.string.ultraprivacy_key) -> {
791                     // Update the icon.
792                     if (sharedPreferences.getBoolean(getString(R.string.ultraprivacy_key), true))
793                         ultraPrivacyPreference.setIcon(R.drawable.block_tracking_enabled)
794                     else
795                         ultraPrivacyPreference.setIcon(R.drawable.block_tracking_disabled)
796                 }
797
798                 getString(R.string.block_all_third_party_requests_key) -> {
799                     // Update the icon.
800                     if (sharedPreferences.getBoolean(getString(R.string.block_all_third_party_requests_key), false)) {
801                         blockAllThirdPartyRequestsPreference.setIcon(R.drawable.block_all_third_party_requests_enabled)
802                     } else {
803                         blockAllThirdPartyRequestsPreference.setIcon(R.drawable.block_all_third_party_requests_disabled)
804                     }
805                 }
806
807                 getString(R.string.tracking_queries_key) -> {
808                     // Update the icon.
809                     if (sharedPreferences.getBoolean(getString(R.string.tracking_queries_key), true))
810                         trackingQueriesPreference.setIcon(R.drawable.modify_url_enabled)
811                     else
812                         trackingQueriesPreference.setIcon(R.drawable.modify_url_disabled)
813                 }
814
815                 getString(R.string.amp_redirects_key) -> {
816                     // Update the icon.
817                     if (sharedPreferences.getBoolean(getString(R.string.amp_redirects_key), true))
818                         ampRedirectsPreference.setIcon(R.drawable.modify_url_enabled)
819                     else
820                         ampRedirectsPreference.setIcon(R.drawable.modify_url_disabled)
821                 }
822
823                 getString(R.string.search_key) -> {
824                     // Store the new search string.
825                     val newSearchString = sharedPreferences.getString(getString(R.string.search_key), getString(R.string.search_default_value))
826
827                     // Update the search and search custom URL preferences.
828                     if (newSearchString == getString(R.string.custom_url_item)) {  // A custom URL is selected.
829                         // Set the summary text to `R.string.custom_url`, which is translated.
830                         searchPreference.setSummary(R.string.custom_url)
831
832                         // Enable the search custom URL preference.
833                         searchCustomURLPreference.isEnabled = true
834
835                         // Set the search custom URL preference icon.
836                         searchCustomURLPreference.setIcon(R.drawable.search_custom_enabled)
837                     } else {  // A custom URL is not selected.
838                         // Set the summary text to the new search string.
839                         searchPreference.summary = newSearchString
840
841                         // Disable the search custom URL Preference.
842                         searchCustomURLPreference.isEnabled = false
843
844                         // Set the search custom URL preference icon.
845                         searchCustomURLPreference.setIcon(R.drawable.search_custom_ghosted)
846                     }
847                 }
848
849                 getString(R.string.search_custom_url_key) -> {
850                     // Set the new search custom URL as the summary text for the preference.
851                     searchCustomURLPreference.summary = sharedPreferences.getString(getString(R.string.search_custom_url_key), getString(R.string.search_custom_url_default_value))
852                 }
853
854                 getString(R.string.proxy_key) -> {
855                     // Get the current proxy string.
856                     val currentProxyString = sharedPreferences.getString(getString(R.string.proxy_key), getString(R.string.proxy_default_value))
857
858                     // Update the proxy preference summary text.
859                     proxyPreference.summary = when (currentProxyString) {
860                         ProxyHelper.NONE -> getString(R.string.no_proxy_enabled)
861                         ProxyHelper.TOR -> getString(R.string.tor_enabled)
862                         ProxyHelper.I2P -> getString(R.string.i2p_enabled)
863                         ProxyHelper.CUSTOM -> getString(R.string.custom_proxy)
864                         else -> getString(R.string.no_proxy_enabled)
865                     }
866
867                     // Update the status of the custom URL preference.
868                     proxyCustomUrlPreference.isEnabled = currentProxyString == ProxyHelper.CUSTOM
869
870                     // Update the icons.
871                     if (currentProxyString == ProxyHelper.NONE) {  // Proxying is disabled.
872                         // Set the main proxy icon to be disabled
873                         proxyPreference.setIcon(R.drawable.proxy_disabled)
874
875                         // Set the custom proxy URL icon to be ghosted.
876                         proxyCustomUrlPreference.setIcon(R.drawable.proxy_ghosted)
877                     } else {  // Proxying is enabled.
878                         // Set the main proxy icon to be enabled.
879                         proxyPreference.setIcon(R.drawable.proxy_enabled)
880
881                         /// Set the custom proxy URL icon according to its status.
882                         if (proxyCustomUrlPreference.isEnabled)
883                             proxyCustomUrlPreference.setIcon(R.drawable.proxy_enabled)
884                         else
885                             proxyCustomUrlPreference.setIcon(R.drawable.proxy_ghosted)
886                     }
887                 }
888
889                 getString(R.string.proxy_custom_url_key) -> {
890                     // Set the summary text for the proxy custom URL.
891                     proxyCustomUrlPreference.summary = sharedPreferences.getString(getString(R.string.proxy_custom_url_key), getString(R.string.proxy_custom_url_default_value))
892                 }
893
894                 getString(R.string.full_screen_browsing_mode_key) -> {
895                     // Update the icons.
896                     if (sharedPreferences.getBoolean(getString(R.string.full_screen_browsing_mode_key), false)) {  // Full screen browsing is enabled.
897                         // Set the full screen browsing mode preference icon.
898                         fullScreenBrowsingModePreference.setIcon(R.drawable.full_screen_enabled)
899
900                         // Set the hide app bar preference icon.
901                         if (sharedPreferences.getBoolean(getString(R.string.hide_app_bar_key), true))
902                             hideAppBarPreference.setIcon(R.drawable.app_bar_enabled)
903                         else
904                             hideAppBarPreference.setIcon(R.drawable.app_bar_disabled)
905                     } else {  // Full screen browsing is disabled.
906                         // Update the icons.
907                         fullScreenBrowsingModePreference.setIcon(R.drawable.full_screen_disabled)
908                         hideAppBarPreference.setIcon(R.drawable.app_bar_ghosted)
909                     }
910                 }
911
912                 getString(R.string.hide_app_bar_key) -> {
913                     // Update the icon.
914                     if (sharedPreferences.getBoolean(getString(R.string.hide_app_bar_key), true))
915                         hideAppBarPreference.setIcon(R.drawable.app_bar_enabled)
916                     else
917                         hideAppBarPreference.setIcon(R.drawable.app_bar_disabled)
918                 }
919
920                 getString(R.string.clear_everything_key) -> {
921                     // Store the new clear everything status
922                     val newClearEverythingBoolean = sharedPreferences.getBoolean(getString(R.string.clear_everything_key), true)
923
924                     // Update the status of the clear and exit preferences.
925                     clearCookiesPreference.isEnabled = !newClearEverythingBoolean
926                     clearDomStoragePreference.isEnabled = !newClearEverythingBoolean
927                     clearFormDataPreference.isEnabled = !newClearEverythingBoolean  // Clear form data can be removed once the minimum API >= 26.
928                     clearLogcatPreference.isEnabled = !newClearEverythingBoolean
929                     clearCachePreference.isEnabled = !newClearEverythingBoolean
930
931                     // Update the clear everything preference icon.
932                     if (newClearEverythingBoolean)
933                         clearEverythingPreference.setIcon(R.drawable.clear_everything_enabled)
934                     else
935                         clearEverythingPreference.setIcon(R.drawable.clear_everything_disabled)
936
937                     // Update the clear cookies preference icon.
938                     if (newClearEverythingBoolean || sharedPreferences.getBoolean(getString(R.string.clear_cookies_key), true))
939                         clearCookiesPreference.setIcon(R.drawable.clear_cookies_enabled)
940                     else
941                         clearCookiesPreference.setIcon(R.drawable.clear_cookies_disabled)
942
943                     // Update the clear dom storage preference icon.
944                     if (newClearEverythingBoolean || sharedPreferences.getBoolean(getString(R.string.clear_dom_storage_key), true))
945                         clearDomStoragePreference.setIcon(R.drawable.clear_dom_storage_enabled)
946                     else
947                         clearDomStoragePreference.setIcon(R.drawable.clear_dom_storage_disabled)
948
949                     // Update the clear form data preference icon if the API < 26.
950                     if (Build.VERSION.SDK_INT < 26) {
951                         if (newClearEverythingBoolean || sharedPreferences.getBoolean(getString(R.string.clear_form_data_key), true))
952                             clearFormDataPreference.setIcon(R.drawable.clear_form_data_enabled)
953                         else
954                             clearFormDataPreference.setIcon(R.drawable.clear_form_data_disabled)
955                     }
956
957                     // Update the clear logcat preference icon.
958                     if (newClearEverythingBoolean || sharedPreferences.getBoolean(getString(R.string.clear_logcat_key), true))
959                         clearLogcatPreference.setIcon(R.drawable.clear_logcat_enabled)
960                     else
961                         clearLogcatPreference.setIcon(R.drawable.clear_logcat_disabled)
962
963                     // Update the clear cache preference icon.
964                     if (newClearEverythingBoolean || sharedPreferences.getBoolean(getString(R.string.clear_cache_key), true))
965                         clearCachePreference.setIcon(R.drawable.clear_cache_enabled)
966                     else
967                         clearCachePreference.setIcon(R.drawable.clear_cache_disabled)
968                 }
969
970                 getString(R.string.clear_cookies_key) -> {
971                     // Update the icon.
972                     if (sharedPreferences.getBoolean(getString(R.string.clear_cookies_key), true))
973                         clearCookiesPreference.setIcon(R.drawable.clear_cookies_enabled)
974                     else
975                         clearCookiesPreference.setIcon(R.drawable.clear_cookies_disabled)
976                 }
977
978                 getString(R.string.clear_dom_storage_key) -> {
979                     // Update the icon.
980                     if (sharedPreferences.getBoolean(getString(R.string.clear_dom_storage_key), true))
981                         clearDomStoragePreference.setIcon(R.drawable.clear_dom_storage_enabled)
982                     else
983                         clearDomStoragePreference.setIcon(R.drawable.clear_dom_storage_disabled)
984                 }
985
986                 getString(R.string.clear_form_data_key) -> {
987                     // Update the icon.
988                     if (sharedPreferences.getBoolean(getString(R.string.clear_form_data_key), true))
989                         clearFormDataPreference.setIcon(R.drawable.clear_form_data_enabled)
990                     else
991                         clearFormDataPreference.setIcon(R.drawable.clear_form_data_disabled)
992                 }
993
994                 getString(R.string.clear_logcat_key) -> {
995                     // Update the icon.
996                     if (sharedPreferences.getBoolean(getString(R.string.clear_logcat_key), true))
997                         clearLogcatPreference.setIcon(R.drawable.clear_logcat_enabled)
998                     else
999                         clearLogcatPreference.setIcon(R.drawable.clear_logcat_disabled)
1000                 }
1001
1002                 getString(R.string.clear_cache_key) -> {
1003                     // Update the icon.
1004                     if (sharedPreferences.getBoolean(getString(R.string.clear_cache_key), true))
1005                         clearCachePreference.setIcon(R.drawable.clear_cache_enabled)
1006                     else
1007                         clearCachePreference.setIcon(R.drawable.clear_cache_disabled)
1008                 }
1009
1010                 getString(R.string.homepage_key) -> {
1011                     // Set the new homepage URL as the summary text for the Homepage preference.
1012                     homepagePreference.summary = sharedPreferences.getString(getString(R.string.homepage_key), getString(R.string.homepage_default_value))
1013                 }
1014
1015                 getString(R.string.font_size_key) -> {
1016                     // Update the font size summary text.
1017                     fontSizePreference.summary = sharedPreferences.getString(getString(R.string.font_size_key), getString(R.string.font_size_default_value)) + "%"
1018                 }
1019
1020                 getString(R.string.open_intents_in_new_tab_key) -> {
1021                     // Update the icon.
1022                     if (sharedPreferences.getBoolean(getString(R.string.open_intents_in_new_tab_key), true))
1023                         openIntentsInNewTabPreference.setIcon(R.drawable.tab_enabled)
1024                     else
1025                         openIntentsInNewTabPreference.setIcon(R.drawable.tab_disabled)
1026                 }
1027
1028                 getString(R.string.swipe_to_refresh_key) -> {
1029                     // Update the icon.
1030                     if (sharedPreferences.getBoolean(getString(R.string.swipe_to_refresh_key), true))
1031                         swipeToRefreshPreference.setIcon(R.drawable.refresh_enabled)
1032                     else
1033                         swipeToRefreshPreference.setIcon(R.drawable.refresh_disabled)
1034                 }
1035
1036                 getString(R.string.download_with_external_app_key) -> {
1037                     // Update the icon.
1038                     if (sharedPreferences.getBoolean(getString(R.string.download_with_external_app_key), false))
1039                         downloadWithExternalAppPreference.setIcon(R.drawable.download_with_external_app_enabled)
1040                     else
1041                         downloadWithExternalAppPreference.setIcon(R.drawable.download_with_external_app_disabled)
1042                 }
1043
1044                 getString(R.string.scroll_app_bar_key) -> {
1045                     // Update the icon.
1046                     if (sharedPreferences.getBoolean(getString(R.string.scroll_app_bar_key), true))
1047                         scrollAppBarPreference.setIcon(R.drawable.app_bar_enabled)
1048                     else
1049                         scrollAppBarPreference.setIcon(R.drawable.app_bar_disabled)
1050                 }
1051
1052                 getString(R.string.bottom_app_bar_key) -> {
1053                     // Update the icon.
1054                     if (sharedPreferences.getBoolean(getString(R.string.bottom_app_bar_key), false))
1055                         bottomAppBarPreference.setIcon(R.drawable.bottom_app_bar_enabled)
1056                     else
1057                         bottomAppBarPreference.setIcon(R.drawable.bottom_app_bar_disabled)
1058
1059                     // Restart Privacy Browser.
1060                     restartPrivacyBrowser()
1061                 }
1062
1063                 getString(R.string.display_additional_app_bar_icons_key) -> {
1064                     // Update the icon.
1065                     if (sharedPreferences.getBoolean(getString(R.string.display_additional_app_bar_icons_key), false))
1066                         displayAdditionalAppBarIconsPreference.setIcon(R.drawable.more_enabled)
1067                     else
1068                         displayAdditionalAppBarIconsPreference.setIcon(R.drawable.more_disabled)
1069                 }
1070
1071                 getString(R.string.app_theme_key) -> {
1072                     // Get the app theme entry number that matches the current app theme.  A switch statement cannot be used because the theme entry values string array is not a compile time constant.
1073                     val appThemeEntryNumber: Int = when (sharedPreferences.getString(getString(R.string.app_theme_key), getString(R.string.app_theme_default_value))) {
1074                         appThemeEntryValuesStringArray[1] -> 1  // The light theme is selected.
1075                         appThemeEntryValuesStringArray[2] -> 2  // The dark theme is selected.
1076                         else -> 0  // The system default theme is selected.
1077                     }
1078
1079                     // Update the system according to the new theme.
1080                     when (appThemeEntryNumber) {
1081                         0 -> {  // The system default theme is selected.
1082                             // Update the theme preference summary text.
1083                             appThemePreference.summary = appThemeEntriesStringArray[0]
1084
1085                             // Apply the new theme.
1086                             if (Build.VERSION.SDK_INT >= 28) {  // The system default theme is supported.
1087                                 // Follow the system default theme.
1088                                 AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
1089                             } else { // The system default theme is not supported.
1090                                 // Follow the battery saver mode.
1091                                 AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_AUTO_BATTERY)
1092                             }
1093                         }
1094
1095                         1 -> {  // The light theme is selected.
1096                             // Update the theme preference summary text.
1097                             appThemePreference.summary = appThemeEntriesStringArray[1]
1098
1099                             // Apply the new theme.
1100                             AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
1101                         }
1102
1103                         2 -> {  // The dark theme is selected.
1104                             // Update the theme preference summary text.
1105                             appThemePreference.summary = appThemeEntriesStringArray[2]
1106
1107                             // Apply the new theme.
1108                             AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
1109                         }
1110                     }
1111
1112                     // Enable the WebView theme preference if the API < 33 or the app theme is set to light.
1113                     webViewThemePreference.isEnabled = ((Build.VERSION.SDK_INT < 33) || (appThemeEntryNumber != 1))
1114
1115                     // Get the webView theme entry number that matches the new WebView theme.
1116                     val webViewThemeEntryNumber: Int = when (sharedPreferences.getString(getString(R.string.webview_theme_key), getString(R.string.webview_theme_default_value))) {
1117                         webViewThemeEntriesStringArray[1] -> 1  // The light theme is selected.
1118                         webViewThemeEntryValuesStringArray[2] -> 2  // The dark theme is selected.
1119                         else -> 0  // The system default theme is selected.
1120                     }
1121
1122                     // Update the WebView theme icon.
1123                     if (webViewThemePreference.isEnabled) {  // The WebView theme preference is enabled.
1124                         when (webViewThemeEntryNumber) {
1125                             // The system default WebView theme is selected.
1126                             0 -> {
1127                                 // Get the current theme status.
1128                                 val currentThemeStatus = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
1129
1130                                 // Set the icon according to the app theme.
1131                                 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO)
1132                                     webViewThemePreference.setIcon(R.drawable.webview_light_theme)
1133                                 else
1134                                     webViewThemePreference.setIcon(R.drawable.webview_dark_theme)
1135                             }
1136
1137                             // The light WebView theme is selected.
1138                             1 -> {
1139                                 // Set the icon.
1140                                 webViewThemePreference.setIcon(R.drawable.webview_light_theme)
1141                             }
1142
1143                             // The dark WebView theme is selected.
1144                             2 -> {
1145                                 // Set the icon.
1146                                 webViewThemePreference.setIcon(R.drawable.webview_dark_theme)
1147                             }
1148                         }
1149                     } else {  // The WebView theme preference is disabled.
1150                         webViewThemePreference.setIcon(R.drawable.webview_theme_ghosted)
1151                     }
1152                 }
1153
1154                 getString(R.string.webview_theme_key) -> {
1155                     // Get the webView theme entry number that matches the new WebView theme.
1156                     val newWebViewThemeEntryNumber: Int = when (sharedPreferences.getString(getString(R.string.webview_theme_key), getString(R.string.webview_theme_default_value))) {
1157                         webViewThemeEntriesStringArray[1] -> 1  // The light theme is selected.
1158                         webViewThemeEntryValuesStringArray[2] -> 2  // The dark theme is selected.
1159                         else -> 0  // The system default theme is selected.
1160                     }
1161
1162                     // Update the WebView theme icon.
1163                     when (newWebViewThemeEntryNumber) {
1164                         // The system default WebView theme is selected.
1165                         0 -> {
1166                             // Get the current theme status.
1167                             val currentThemeStatus = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
1168
1169                             // Set the icon.
1170                             if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO)
1171                                 webViewThemePreference.setIcon(R.drawable.webview_light_theme)
1172                             else
1173                                 webViewThemePreference.setIcon(R.drawable.webview_dark_theme)
1174                         }
1175
1176                         // The light WebView theme is selected.
1177                         1 -> {
1178                             // Set the icon.
1179                             webViewThemePreference.setIcon(R.drawable.webview_light_theme)
1180                         }
1181
1182                         // The dark WebView theme is selected.
1183                         2 -> {
1184                             // Set the icon.
1185                             webViewThemePreference.setIcon(R.drawable.webview_dark_theme)
1186                         }
1187                     }
1188
1189                     // Set the current theme as the summary text for the preference.
1190                     webViewThemePreference.summary = webViewThemeEntriesStringArray[newWebViewThemeEntryNumber]
1191                 }
1192
1193                 getString(R.string.wide_viewport_key) -> {
1194                     // Update the icon.
1195                     if (sharedPreferences.getBoolean(getString(R.string.wide_viewport_key), true))
1196                         wideViewportPreference.setIcon(R.drawable.wide_viewport_enabled)
1197                     else
1198                         wideViewportPreference.setIcon(R.drawable.wide_viewport_disabled)
1199                 }
1200
1201                 getString(R.string.display_webpage_images_key) -> {
1202                     // Update the icon.
1203                     if (sharedPreferences.getBoolean(getString(R.string.display_webpage_images_key), true))
1204                         displayWebpageImagesPreference.setIcon(R.drawable.images_enabled)
1205                     else
1206                         displayWebpageImagesPreference.setIcon(R.drawable.images_disabled)
1207                 }
1208             }
1209         }
1210     }
1211
1212     private fun restartPrivacyBrowser() {
1213         // Create an intent to restart Privacy Browser.
1214         val restartIntent = requireActivity().parentActivityIntent!!
1215
1216         // `Intent.FLAG_ACTIVITY_CLEAR_TASK` removes all activities from the stack.  It requires `Intent.FLAG_ACTIVITY_NEW_TASK`.
1217         restartIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
1218
1219         // Create a handler to restart the activity.
1220         val restartHandler = Handler(Looper.getMainLooper())
1221
1222         // Create a runnable to restart the activity.
1223         val restartRunnable = Runnable {
1224             // Restart the activity.
1225             startActivity(restartIntent)
1226
1227             // Kill this instance of Privacy Browser.  Otherwise, the app exhibits sporadic behavior after the restart.
1228             exitProcess(0)
1229         }
1230
1231         // Restart the activity after 400 milliseconds, so that the app has enough time to save the change to the preference.
1232         restartHandler.postDelayed(restartRunnable, 400)
1233     }
1234 }