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