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