2 * Copyright 2016-2022 Soren Stoutner <soren@stoutner.com>.
4 * This file is part of Privacy Browser Android <https://www.stoutner.com/privacy-browser-android>.
6 * Privacy Browser Android is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * Privacy Browser Android is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with Privacy Browser Android. If not, see <http://www.gnu.org/licenses/>.
20 package com.stoutner.privacybrowser.fragments
22 import android.annotation.SuppressLint
23 import android.content.Intent
24 import android.content.SharedPreferences
25 import android.content.SharedPreferences.OnSharedPreferenceChangeListener
26 import android.content.res.Configuration
27 import android.os.Build
28 import android.os.Bundle
29 import android.os.Handler
30 import android.os.Looper
31 import android.webkit.WebView
32 import android.widget.ArrayAdapter
34 import androidx.appcompat.app.AppCompatDelegate
35 import androidx.preference.Preference
36 import androidx.preference.PreferenceCategory
37 import androidx.preference.PreferenceFragmentCompat
39 import com.stoutner.privacybrowser.R
40 import com.stoutner.privacybrowser.activities.MainWebViewActivity
41 import com.stoutner.privacybrowser.helpers.ProxyHelper
42 import kotlin.system.exitProcess
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>
56 // Define the the class views.
57 private lateinit var javaScriptPreference: Preference
58 private lateinit var cookiesPreference: Preference
59 private lateinit var domStoragePreference: Preference
60 private lateinit var formDataPreference: Preference // The form data preference can be removed once the minimum API >= 26.
61 private lateinit var userAgentPreference: Preference
62 private lateinit var customUserAgentPreference: Preference
63 private lateinit var xRequestedWithHeaderPreference: Preference
64 private lateinit var incognitoModePreference: Preference
65 private lateinit var allowScreenshotsPreference: Preference
66 private lateinit var easyListPreference: Preference
67 private lateinit var easyPrivacyPreference: Preference
68 private lateinit var fanboyAnnoyanceListPreference: Preference
69 private lateinit var fanboySocialBlockingListPreference: Preference
70 private lateinit var ultraListPreference: Preference
71 private lateinit var ultraPrivacyPreference: Preference
72 private lateinit var blockAllThirdPartyRequestsPreference: Preference
73 private lateinit var trackingQueriesPreference: Preference
74 private lateinit var ampRedirectsPreference: Preference
75 private lateinit var searchPreference: Preference
76 private lateinit var searchCustomURLPreference: Preference
77 private lateinit var proxyPreference: Preference
78 private lateinit var proxyCustomUrlPreference: Preference
79 private lateinit var fullScreenBrowsingModePreference: Preference
80 private lateinit var hideAppBarPreference: Preference
81 private lateinit var clearEverythingPreference: Preference
82 private lateinit var clearCookiesPreference: Preference
83 private lateinit var clearDomStoragePreference: Preference
84 private lateinit var clearFormDataPreference: Preference // The clear form data preference can be removed once the minimum API >= 26.
85 private lateinit var clearLogcatPreference: Preference
86 private lateinit var clearCachePreference: Preference
87 private lateinit var homepagePreference: Preference
88 private lateinit var fontSizePreference: Preference
89 private lateinit var openIntentsInNewTabPreference: Preference
90 private lateinit var swipeToRefreshPreference: Preference
91 private lateinit var downloadWithExternalAppPreference: Preference
92 private lateinit var scrollAppBarPreference: Preference
93 private lateinit var bottomAppBarPreference: Preference
94 private lateinit var displayAdditionalAppBarIconsPreference: Preference
95 private lateinit var appThemePreference: Preference
96 private lateinit var webViewThemePreference: Preference
97 private lateinit var wideViewportPreference: Preference
98 private lateinit var displayWebpageImagesPreference: Preference
100 override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
101 // Load the preferences from the XML file.
102 setPreferencesFromResource(R.xml.preferences, rootKey)
104 // Get a handle for the shared preferences.
105 val sharedPreferences = preferenceScreen.sharedPreferences!!
107 // Get handles for the preferences.
108 javaScriptPreference = findPreference(getString(R.string.javascript_key))!!
109 cookiesPreference = findPreference(getString(R.string.cookies_key))!!
110 domStoragePreference = findPreference(getString(R.string.dom_storage_key))!!
111 formDataPreference = findPreference(getString(R.string.save_form_data_key))!! // The form data preference can be removed once the minimum API >= 26.
112 userAgentPreference = findPreference(getString(R.string.user_agent_key))!!
113 customUserAgentPreference = findPreference(getString(R.string.custom_user_agent_key))!!
114 xRequestedWithHeaderPreference = findPreference(getString(R.string.x_requested_with_header_key))!!
115 incognitoModePreference = findPreference(getString(R.string.incognito_mode_key))!!
116 allowScreenshotsPreference = findPreference(getString(R.string.allow_screenshots_key))!!
117 easyListPreference = findPreference(getString(R.string.easylist_key))!!
118 easyPrivacyPreference = findPreference(getString(R.string.easyprivacy_key))!!
119 fanboyAnnoyanceListPreference = findPreference(getString(R.string.fanboys_annoyance_list_key))!!
120 fanboySocialBlockingListPreference = findPreference(getString(R.string.fanboys_social_blocking_list_key))!!
121 ultraListPreference = findPreference(getString(R.string.ultralist_key))!!
122 ultraPrivacyPreference = findPreference(getString(R.string.ultraprivacy_key))!!
123 blockAllThirdPartyRequestsPreference = findPreference(getString(R.string.block_all_third_party_requests_key))!!
124 trackingQueriesPreference = findPreference(getString(R.string.tracking_queries_key))!!
125 ampRedirectsPreference = findPreference(getString(R.string.amp_redirects_key))!!
126 searchPreference = findPreference(getString(R.string.search_key))!!
127 searchCustomURLPreference = findPreference(getString(R.string.search_custom_url_key))!!
128 proxyPreference = findPreference(getString(R.string.proxy_key))!!
129 proxyCustomUrlPreference = findPreference(getString(R.string.proxy_custom_url_key))!!
130 fullScreenBrowsingModePreference = findPreference(getString(R.string.full_screen_browsing_mode_key))!!
131 hideAppBarPreference = findPreference(getString(R.string.hide_app_bar_key))!!
132 clearEverythingPreference = findPreference(getString(R.string.clear_everything_key))!!
133 clearCookiesPreference = findPreference(getString(R.string.clear_cookies_key))!!
134 clearDomStoragePreference = findPreference(getString(R.string.clear_dom_storage_key))!!
135 clearFormDataPreference = findPreference(getString(R.string.clear_form_data_key))!! // The clear form data preference can be removed once the minimum API >= 26.
136 clearLogcatPreference = findPreference(getString(R.string.clear_logcat_key))!!
137 clearCachePreference = findPreference(getString(R.string.clear_cache_key))!!
138 homepagePreference = findPreference(getString(R.string.homepage_key))!!
139 fontSizePreference = findPreference(getString(R.string.font_size_key))!!
140 openIntentsInNewTabPreference = findPreference(getString(R.string.open_intents_in_new_tab_key))!!
141 swipeToRefreshPreference = findPreference(getString(R.string.swipe_to_refresh_key))!!
142 downloadWithExternalAppPreference = findPreference(getString(R.string.download_with_external_app_key))!!
143 scrollAppBarPreference = findPreference(getString(R.string.scroll_app_bar_key))!!
144 bottomAppBarPreference = findPreference(getString(R.string.bottom_app_bar_key))!!
145 displayAdditionalAppBarIconsPreference = findPreference(getString(R.string.display_additional_app_bar_icons_key))!!
146 appThemePreference = findPreference(getString(R.string.app_theme_key))!!
147 webViewThemePreference = findPreference(getString(R.string.webview_theme_key))!!
148 wideViewportPreference = findPreference(getString(R.string.wide_viewport_key))!!
149 displayWebpageImagesPreference = findPreference(getString(R.string.display_webpage_images_key))!!
151 // Set the preference dependencies.
152 domStoragePreference.dependency = getString(R.string.javascript_key)
153 hideAppBarPreference.dependency = getString(R.string.full_screen_browsing_mode_key)
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))
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)
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))!!
173 // Remove the form data preferences.
174 privacyCategory.removePreference(formDataPreference)
175 clearAndExitCategory.removePreference(clearFormDataPreference)
178 // Only enable Fanboy's social blocking list preference if Fanboy's annoyance list is disabled.
179 fanboySocialBlockingListPreference.isEnabled = !fanboyAnnoyanceListEnabled
182 // Inflate a WebView to get the default user agent.
183 val inflater = requireActivity().layoutInflater
185 // `@SuppressLint("InflateParams")` removes the warning about using `null` as the `ViewGroup`, which in this case makes sense because the `bare_webview` will not be displayed.
186 @SuppressLint("InflateParams") val bareWebViewLayout = inflater.inflate(R.layout.bare_webview, null, false)
188 // Get a handle for the bare WebView.
189 val bareWebView = bareWebViewLayout.findViewById<WebView>(R.id.bare_webview)
191 // Get the default user agent.
192 defaultUserAgent = bareWebView.settings.userAgentString
194 // Get the user agent arrays.
195 userAgentNamesArray = ArrayAdapter.createFromResource(requireContext(), R.array.user_agent_names, R.layout.spinner_item)
196 translatedUserAgentNamesArray = resources.getStringArray(R.array.translated_user_agent_names)
197 userAgentDataArray = resources.getStringArray(R.array.user_agent_data)
199 // Populate the user agent summary.
200 when (val userAgentArrayPosition = userAgentNamesArray.getPosition(userAgentName)) {
201 // The user agent name is not on the canonical list.
202 // This is probably because it was set in an older version of Privacy Browser before the switch to persistent user agent names. Use the current user agent entry name as the summary.
203 MainWebViewActivity.UNRECOGNIZED_USER_AGENT -> userAgentPreference.summary = userAgentName
205 // Get the user agent text from the webview (which changes based on the version of Android and WebView installed).
206 MainWebViewActivity.SETTINGS_WEBVIEW_DEFAULT_USER_AGENT -> userAgentPreference.summary = "${translatedUserAgentNamesArray[userAgentArrayPosition]}:\n$defaultUserAgent"
208 // Display the custom user agent.
209 MainWebViewActivity.SETTINGS_CUSTOM_USER_AGENT -> userAgentPreference.setSummary(R.string.custom_user_agent)
211 // Get the user agent summary from the user agent data array.
212 else -> userAgentPreference.summary = "${translatedUserAgentNamesArray[userAgentArrayPosition]}:\n${userAgentDataArray[userAgentArrayPosition]}"
215 // Set the summary text for the custom user agent preference.
216 customUserAgentPreference.summary = sharedPreferences.getString(getString(R.string.custom_user_agent_key), getString(R.string.custom_user_agent_default_value))
218 // Only enable the custom user agent preference if the user agent is set to custom.
219 customUserAgentPreference.isEnabled = (userAgentPreference.summary == getString(R.string.custom_user_agent))
221 // Set the search URL as the summary text for the search preference when the preference screen is loaded.
222 if (searchString == getString(R.string.custom_url_item)) {
223 // Use R.string.custom_url, which will be translated, instead of the array value, which will not.
224 searchPreference.setSummary(R.string.custom_url)
226 // Set the array value as the summary text.
227 searchPreference.summary = searchString
230 // Set the summary text for the search custom URL (the default is `""`).
231 searchCustomURLPreference.summary = sharedPreferences.getString(getString(R.string.search_custom_url_key), getString(R.string.search_custom_url_default_value))
233 // Only enable the search custom URL preference if the search is set to a custom URL.
234 searchCustomURLPreference.isEnabled = (searchString == getString(R.string.custom_url_item))
236 // Set the summary text for the proxy preference.
237 proxyPreference.summary = when (proxyString) {
238 ProxyHelper.NONE -> getString(R.string.no_proxy_enabled)
239 ProxyHelper.TOR -> getString(R.string.tor_enabled)
240 ProxyHelper.I2P -> getString(R.string.i2p_enabled)
241 ProxyHelper.CUSTOM -> getString(R.string.custom_proxy)
242 else -> getString(R.string.no_proxy_enabled)
245 // Set the summary text for the custom proxy URL.
246 proxyCustomUrlPreference.summary = sharedPreferences.getString(getString(R.string.proxy_custom_url_key), getString(R.string.proxy_custom_url_default_value))
248 // Only enable the custom proxy URL if a custom proxy is selected.
249 proxyCustomUrlPreference.isEnabled = proxyString == ProxyHelper.CUSTOM
251 // Set the status of the clear and exit preferences.
252 clearCookiesPreference.isEnabled = !clearEverything
253 clearDomStoragePreference.isEnabled = !clearEverything
254 clearFormDataPreference.isEnabled = !clearEverything // Clear form data can be removed once the minimum API is >= 26.
255 clearLogcatPreference.isEnabled = !clearEverything
256 clearCachePreference.isEnabled = !clearEverything
258 // Set the homepage URL as the summary text for the homepage preference.
259 homepagePreference.summary = sharedPreferences.getString(getString(R.string.homepage_key), getString(R.string.homepage_default_value))
261 // Set the font size as the summary text for the preference.
262 fontSizePreference.summary = sharedPreferences.getString(getString(R.string.font_size_key), getString(R.string.font_size_default_value)) + "%"
264 // Get the app theme string arrays.
265 appThemeEntriesStringArray = resources.getStringArray(R.array.app_theme_entries)
266 appThemeEntryValuesStringArray = resources.getStringArray(R.array.app_theme_entry_values)
268 // Get the app theme entry number that matches the current app theme.
269 val appThemeEntryNumber: Int = when (sharedPreferences.getString(getString(R.string.app_theme_key), getString(R.string.app_theme_default_value))) {
270 appThemeEntryValuesStringArray[1] -> 1 // The light theme is selected.
271 appThemeEntryValuesStringArray[2] -> 2 // The dark theme is selected.
272 else -> 0 // The system default theme is selected.
275 // Set the current theme as the summary text for the preference.
276 appThemePreference.summary = appThemeEntriesStringArray[appThemeEntryNumber]
278 // Enable the WebView theme preference if the API < 33 or the app theme is not set to light. Google no longer allows light themes to display dark WebViews.
279 webViewThemePreference.isEnabled = ((Build.VERSION.SDK_INT < 33) || (appThemeEntryNumber != 1))
281 // Get the WebView theme string arrays.
282 webViewThemeEntriesStringArray = resources.getStringArray(R.array.webview_theme_entries)
283 webViewThemeEntryValuesStringArray = resources.getStringArray(R.array.webview_theme_entry_values)
285 // Get the WebView theme entry number that matches the current WebView theme.
286 val webViewThemeEntryNumber: Int = when (sharedPreferences.getString(getString(R.string.webview_theme_key), getString(R.string.webview_theme_default_value))) {
287 webViewThemeEntryValuesStringArray[1] -> 1 // The light theme is selected.
288 webViewThemeEntryValuesStringArray[2] -> 2 // The dark theme is selected.
289 else -> 0 // The system default theme is selected.
292 // Set the current theme as the summary text for the preference.
293 webViewThemePreference.summary = webViewThemeEntriesStringArray[webViewThemeEntryNumber]
295 // Set the JavaScript icon.
296 if (javaScriptEnabled)
297 javaScriptPreference.setIcon(R.drawable.javascript_enabled)
299 javaScriptPreference.setIcon(R.drawable.privacy_mode)
301 // Set the cookies icon.
302 if (sharedPreferences.getBoolean(getString(R.string.cookies_key), false))
303 cookiesPreference.setIcon(R.drawable.cookies_enabled)
305 cookiesPreference.setIcon(R.drawable.cookies_disabled)
307 // Set the DOM storage icon.
308 if (javaScriptEnabled) { // JavaScript is enabled.
309 if (sharedPreferences.getBoolean(getString(R.string.dom_storage_key), false)) // DOM storage is enabled.
310 domStoragePreference.setIcon(R.drawable.dom_storage_enabled)
311 else // DOM storage is disabled.
312 domStoragePreference.setIcon(R.drawable.dom_storage_disabled)
313 } else { // JavaScript is disabled. DOM storage should be ghosted.
314 domStoragePreference.setIcon(R.drawable.dom_storage_ghosted)
317 // Set the save form data icon if API < 26. Save form data has no effect on API >= 26.
318 if (Build.VERSION.SDK_INT < 26) {
319 if (sharedPreferences.getBoolean(getString(R.string.save_form_data_key), false))
320 formDataPreference.setIcon(R.drawable.form_data_enabled)
322 formDataPreference.setIcon(R.drawable.form_data_disabled)
325 // Set the custom user agent icon.
326 if (customUserAgentPreference.isEnabled)
327 customUserAgentPreference.setIcon(R.drawable.custom_user_agent_enabled)
329 customUserAgentPreference.setIcon(R.drawable.custom_user_agent_ghosted)
331 // Set the X-Requested With header icon.
332 if (sharedPreferences.getBoolean(getString(R.string.x_requested_with_header_key), true))
333 xRequestedWithHeaderPreference.setIcon(R.drawable.x_requested_with_header_enabled)
335 xRequestedWithHeaderPreference.setIcon(R.drawable.x_requested_with_header_disabled)
337 // Set the incognito mode icon.
338 if (sharedPreferences.getBoolean(getString(R.string.incognito_mode_key), false))
339 incognitoModePreference.setIcon(R.drawable.incognito_mode_enabled)
341 incognitoModePreference.setIcon(R.drawable.incognito_mode_disabled)
343 // Set the allow screenshots icon.
344 if (sharedPreferences.getBoolean(getString(R.string.allow_screenshots_key), false))
345 allowScreenshotsPreference.setIcon(R.drawable.allow_screenshots_enabled)
347 allowScreenshotsPreference.setIcon(R.drawable.allow_screenshots_disabled)
349 // Set the EasyList icon.
350 if (sharedPreferences.getBoolean(getString(R.string.easylist_key), true))
351 easyListPreference.setIcon(R.drawable.block_ads_enabled)
353 easyListPreference.setIcon(R.drawable.block_ads_disabled)
355 // Set the EasyPrivacy icon.
356 if (sharedPreferences.getBoolean(getString(R.string.easyprivacy_key), true))
357 easyPrivacyPreference.setIcon(R.drawable.block_tracking_enabled)
359 easyPrivacyPreference.setIcon(R.drawable.block_tracking_disabled)
361 // Set the Fanboy lists icons.
362 if (fanboyAnnoyanceListEnabled) {
363 // Set the Fanboy annoyance list icon.
364 fanboyAnnoyanceListPreference.setIcon(R.drawable.social_media_enabled)
366 // Set the Fanboy social blocking list icon.
367 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_ghosted)
369 // Set the Fanboy annoyance list icon.
370 fanboyAnnoyanceListPreference.setIcon(R.drawable.social_media_disabled)
372 // Set the Fanboy social blocking list icon.
373 if (fanboySocialBlockingEnabled)
374 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_enabled)
376 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_disabled)
379 // Set the UltraList icon.
380 if (sharedPreferences.getBoolean(getString(R.string.ultralist_key), true))
381 ultraListPreference.setIcon(R.drawable.block_ads_enabled)
383 ultraListPreference.setIcon(R.drawable.block_ads_disabled)
385 // Set the UltraPrivacy icon.
386 if (sharedPreferences.getBoolean(getString(R.string.ultraprivacy_key), true))
387 ultraPrivacyPreference.setIcon(R.drawable.block_tracking_enabled)
389 ultraPrivacyPreference.setIcon(R.drawable.block_tracking_disabled)
391 // Set the block all third-party requests icon.
392 if (sharedPreferences.getBoolean(getString(R.string.block_all_third_party_requests), false))
393 blockAllThirdPartyRequestsPreference.setIcon(R.drawable.block_all_third_party_requests_enabled)
395 blockAllThirdPartyRequestsPreference.setIcon(R.drawable.block_all_third_party_requests_disabled)
397 // Set the Tracking Queries icon.
398 if (sharedPreferences.getBoolean(getString(R.string.tracking_queries_key), true))
399 trackingQueriesPreference.setIcon(R.drawable.modify_url_enabled)
401 trackingQueriesPreference.setIcon(R.drawable.modify_url_disabled)
403 // Set the AMP Redirects icon.
404 if (sharedPreferences.getBoolean(getString(R.string.amp_redirects_key), true))
405 ampRedirectsPreference.setIcon(R.drawable.modify_url_enabled)
407 ampRedirectsPreference.setIcon(R.drawable.modify_url_disabled)
409 // Set the search custom URL icon.
410 if (searchCustomURLPreference.isEnabled)
411 searchCustomURLPreference.setIcon(R.drawable.search_custom_enabled)
413 searchCustomURLPreference.setIcon(R.drawable.search_custom_ghosted)
415 // Set the proxy icons according to the theme and status.
416 if (proxyString == ProxyHelper.NONE) { // Proxying is disabled.
417 // Set the main proxy icon to be disabled.
418 proxyPreference.setIcon(R.drawable.proxy_disabled)
420 // Set the custom proxy URL icon to be ghosted.
421 proxyCustomUrlPreference.setIcon(R.drawable.proxy_ghosted)
422 } else { // Proxying is enabled.
423 // Set the main proxy icon to be enabled.
424 proxyPreference.setIcon(R.drawable.proxy_enabled)
426 // Set the custom proxy URL icon according to its status.
427 if (proxyCustomUrlPreference.isEnabled)
428 proxyCustomUrlPreference.setIcon(R.drawable.proxy_enabled)
430 proxyCustomUrlPreference.setIcon(R.drawable.proxy_ghosted)
433 // Set the full-screen browsing mode icons.
434 if (fullScreenBrowsingMode) { // Full-screen browsing mode is enabled.
435 // Set the full screen browsing mode preference icon.
436 fullScreenBrowsingModePreference.setIcon(R.drawable.full_screen_enabled)
438 // Set the hide app bar icon.
439 if (sharedPreferences.getBoolean(getString(R.string.hide_app_bar_key), true))
440 hideAppBarPreference.setIcon(R.drawable.app_bar_enabled)
442 hideAppBarPreference.setIcon(R.drawable.app_bar_disabled)
443 } else { // Full screen browsing mode is disabled.
445 fullScreenBrowsingModePreference.setIcon(R.drawable.full_screen_disabled)
446 hideAppBarPreference.setIcon(R.drawable.app_bar_ghosted)
449 // Set the clear everything icon.
450 if (clearEverything) {
451 clearEverythingPreference.setIcon(R.drawable.clear_everything_enabled)
453 clearEverythingPreference.setIcon(R.drawable.clear_everything_disabled)
456 // Set the clear cookies icon.
457 if (clearEverything || sharedPreferences.getBoolean(getString(R.string.clear_cookies_key), true))
458 clearCookiesPreference.setIcon(R.drawable.clear_cookies_enabled)
460 clearCookiesPreference.setIcon(R.drawable.clear_cookies_disabled)
462 // Set the clear DOM storage icon.
463 if (clearEverything || sharedPreferences.getBoolean(getString(R.string.clear_dom_storage_key), true))
464 clearDomStoragePreference.setIcon(R.drawable.clear_dom_storage_enabled)
466 clearDomStoragePreference.setIcon(R.drawable.clear_dom_storage_disabled)
468 // Set the clear form data icon if the API < 26. It has no effect on newer versions of Android.
469 if (Build.VERSION.SDK_INT < 26) {
470 if (clearEverything || sharedPreferences.getBoolean(getString(R.string.clear_form_data_key), true))
471 clearFormDataPreference.setIcon(R.drawable.clear_form_data_enabled)
473 clearFormDataPreference.setIcon(R.drawable.clear_form_data_disabled)
476 // Set the clear logcat icon.
477 if (clearEverything || sharedPreferences.getBoolean(getString(R.string.clear_logcat_key), true))
478 clearLogcatPreference.setIcon(R.drawable.clear_logcat_enabled)
480 clearLogcatPreference.setIcon(R.drawable.clear_logcat_disabled)
482 // Set the clear cache icon.
483 if (clearEverything || sharedPreferences.getBoolean(getString(R.string.clear_cache_key), true))
484 clearCachePreference.setIcon(R.drawable.clear_cache_enabled)
486 clearCachePreference.setIcon(R.drawable.clear_cache_disabled)
488 // Set the open intents in new tab icon.
489 if (sharedPreferences.getBoolean(getString(R.string.open_intents_in_new_tab_key), true))
490 openIntentsInNewTabPreference.setIcon(R.drawable.tab_enabled)
492 openIntentsInNewTabPreference.setIcon(R.drawable.tab_disabled)
494 // Set the swipe to refresh icon.
495 if (sharedPreferences.getBoolean(getString(R.string.swipe_to_refresh_key), true))
496 swipeToRefreshPreference.setIcon(R.drawable.refresh_enabled)
498 swipeToRefreshPreference.setIcon(R.drawable.refresh_disabled)
500 // Set the download with external app icon.
501 if (sharedPreferences.getBoolean(getString(R.string.download_with_external_app_key), false))
502 downloadWithExternalAppPreference.setIcon(R.drawable.download_with_external_app_enabled)
504 downloadWithExternalAppPreference.setIcon(R.drawable.download_with_external_app_disabled)
506 // Set the scroll app bar icon.
507 if (sharedPreferences.getBoolean(getString(R.string.scroll_app_bar_key), true))
508 scrollAppBarPreference.setIcon(R.drawable.app_bar_enabled)
510 scrollAppBarPreference.setIcon(R.drawable.app_bar_disabled)
512 // Set the bottom app bar icon.
513 if (sharedPreferences.getBoolean(getString(R.string.bottom_app_bar_key), false))
514 bottomAppBarPreference.setIcon(R.drawable.bottom_app_bar_enabled)
516 bottomAppBarPreference.setIcon(R.drawable.bottom_app_bar_disabled)
518 // Set the display additional app bar icons icon.
519 if (sharedPreferences.getBoolean(getString(R.string.display_additional_app_bar_icons_key), false))
520 displayAdditionalAppBarIconsPreference.setIcon(R.drawable.more_enabled)
522 displayAdditionalAppBarIconsPreference.setIcon(R.drawable.more_disabled)
524 // Set the WebView theme icon.
525 if (webViewThemePreference.isEnabled) { // The WebView theme preference is enabled.
526 when (webViewThemeEntryNumber) {
527 // The system default WebView theme is selected.
529 // Get the current theme status.
530 val currentThemeStatus = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
532 // Set the icon according to the app theme.
533 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO)
534 webViewThemePreference.setIcon(R.drawable.webview_light_theme)
536 webViewThemePreference.setIcon(R.drawable.webview_dark_theme)
539 // The light WebView theme is selected.
542 webViewThemePreference.setIcon(R.drawable.webview_light_theme)
545 // The dark WebView theme is selected.
548 webViewThemePreference.setIcon(R.drawable.webview_dark_theme)
551 } else { // The WebView theme preference is disabled.
552 webViewThemePreference.setIcon(R.drawable.webview_theme_ghosted)
555 // Set the wide viewport icon.
556 if (sharedPreferences.getBoolean(getString(R.string.wide_viewport_key), true))
557 wideViewportPreference.setIcon(R.drawable.wide_viewport_enabled)
559 wideViewportPreference.setIcon(R.drawable.wide_viewport_disabled)
561 // Set the display webpage images icon.
562 if (sharedPreferences.getBoolean(getString(R.string.display_webpage_images_key), true))
563 displayWebpageImagesPreference.setIcon(R.drawable.images_enabled)
565 displayWebpageImagesPreference.setIcon(R.drawable.images_disabled)
568 // The listener should be unregistered when the app is paused.
569 override fun onPause() {
570 // Run the default commands.
573 // Get a handle for the shared preferences.
574 val sharedPreferences = preferenceScreen.sharedPreferences!!
576 // Unregister the shared preference listener.
577 sharedPreferences.unregisterOnSharedPreferenceChangeListener(sharedPreferenceChangeListener)
580 // The listener should be re-registered when the app is resumed.
581 override fun onResume() {
582 // Run the default commands.
585 // Get a new shared preference change listener.
586 sharedPreferenceChangeListener = getSharedPreferenceChangeListener()
588 // Get a handle for the shared preferences.
589 val sharedPreferences = preferenceScreen.sharedPreferences!!
591 // Re-register the shared preference listener.
592 sharedPreferences.registerOnSharedPreferenceChangeListener(sharedPreferenceChangeListener)
595 private fun getSharedPreferenceChangeListener(): OnSharedPreferenceChangeListener {
596 // Return the shared preference change listener.
597 return OnSharedPreferenceChangeListener { sharedPreferences: SharedPreferences, key: String? ->
599 getString(R.string.javascript_key) -> {
600 // Update the icons and the DOM storage preference status.
601 if (sharedPreferences.getBoolean(getString(R.string.javascript_key), false)) { // The JavaScript preference is enabled.
602 // Update the icon for the JavaScript preference.
603 javaScriptPreference.setIcon(R.drawable.javascript_enabled)
605 // Update the status of the DOM storage preference.
606 domStoragePreference.isEnabled = true
608 // Update the icon for the DOM storage preference.
609 if (sharedPreferences.getBoolean(getString(R.string.dom_storage_key), false))
610 domStoragePreference.setIcon(R.drawable.dom_storage_enabled)
612 domStoragePreference.setIcon(R.drawable.dom_storage_disabled)
613 } else { // The JavaScript preference is disabled.
614 // Update the icon for the JavaScript preference.
615 javaScriptPreference.setIcon(R.drawable.privacy_mode)
617 // Update the status of the DOM storage preference.
618 domStoragePreference.isEnabled = false
620 // Set the icon for DOM storage preference to be ghosted.
621 domStoragePreference.setIcon(R.drawable.dom_storage_ghosted)
625 getString(R.string.cookies_key) -> {
627 if (sharedPreferences.getBoolean(getString(R.string.cookies_key), false))
628 cookiesPreference.setIcon(R.drawable.cookies_enabled)
630 cookiesPreference.setIcon(R.drawable.cookies_disabled)
633 getString(R.string.dom_storage_key) -> {
635 if (sharedPreferences.getBoolean(getString(R.string.dom_storage_key), false))
636 domStoragePreference.setIcon(R.drawable.dom_storage_enabled)
638 domStoragePreference.setIcon(R.drawable.dom_storage_disabled)
641 getString(R.string.save_form_data_key) -> { // Saved form data can be removed once the minimum API >= 26.
643 if (sharedPreferences.getBoolean(getString(R.string.save_form_data_key), false))
644 formDataPreference.setIcon(R.drawable.form_data_enabled)
646 formDataPreference.setIcon(R.drawable.form_data_disabled)
649 getString(R.string.user_agent_key) -> {
650 // Get the new user agent name.
651 val newUserAgentName = sharedPreferences.getString(getString(R.string.user_agent_key), getString(R.string.user_agent_default_value))
653 // Get the array position for the new user agent name.
654 val newUserAgentArrayPosition = userAgentNamesArray.getPosition(newUserAgentName)
656 // Get the translated new user agent name.
657 val translatedNewUserAgentName = translatedUserAgentNamesArray[newUserAgentArrayPosition]
659 // Populate the user agent summary.
660 when (newUserAgentArrayPosition) {
661 MainWebViewActivity.SETTINGS_WEBVIEW_DEFAULT_USER_AGENT -> {
662 // Get the user agent text from the webview (which changes based on the version of Android and WebView installed).
663 userAgentPreference.summary = "$translatedNewUserAgentName:\n$defaultUserAgent"
665 // Disable the custom user agent preference.
666 customUserAgentPreference.isEnabled = false
668 // Set the custom user agent preference icon.
669 customUserAgentPreference.setIcon(R.drawable.custom_user_agent_ghosted)
672 MainWebViewActivity.SETTINGS_CUSTOM_USER_AGENT -> {
673 // Set the summary text.
674 userAgentPreference.setSummary(R.string.custom_user_agent)
676 // Enable the custom user agent preference.
677 customUserAgentPreference.isEnabled = true
679 // Set the custom user agent preference icon.
680 customUserAgentPreference.setIcon(R.drawable.custom_user_agent_enabled)
684 // Get the user agent summary from the user agent data array.
685 userAgentPreference.summary = "$translatedNewUserAgentName:\n${userAgentDataArray[newUserAgentArrayPosition]}"
687 // Disable the custom user agent preference.
688 customUserAgentPreference.isEnabled = false
690 // Set the custom user agent preference icon.
691 customUserAgentPreference.setIcon(R.drawable.custom_user_agent_ghosted)
696 getString(R.string.custom_user_agent_key) -> {
697 // Set the new custom user agent as the summary text for the preference.
698 customUserAgentPreference.summary = sharedPreferences.getString(getString(R.string.custom_user_agent_key), getString(R.string.custom_user_agent_default_value))
701 getString(R.string.x_requested_with_header_key) -> {
703 if (sharedPreferences.getBoolean(getString(R.string.x_requested_with_header_key), true))
704 xRequestedWithHeaderPreference.setIcon(R.drawable.x_requested_with_header_enabled)
706 xRequestedWithHeaderPreference.setIcon(R.drawable.x_requested_with_header_disabled)
708 // Restart Privacy Browser.
709 restartPrivacyBrowser()
712 getString(R.string.incognito_mode_key) -> {
714 if (sharedPreferences.getBoolean(getString(R.string.incognito_mode_key), false))
715 incognitoModePreference.setIcon(R.drawable.incognito_mode_enabled)
717 incognitoModePreference.setIcon(R.drawable.incognito_mode_disabled)
720 getString(R.string.allow_screenshots_key) -> {
722 if (sharedPreferences.getBoolean(getString(R.string.allow_screenshots_key), false))
723 allowScreenshotsPreference.setIcon(R.drawable.allow_screenshots_enabled)
725 allowScreenshotsPreference.setIcon(R.drawable.allow_screenshots_disabled)
727 // Restart Privacy Browser.
728 restartPrivacyBrowser()
731 getString(R.string.easylist_key) -> {
733 if (sharedPreferences.getBoolean(getString(R.string.easylist_key), true))
734 easyListPreference.setIcon(R.drawable.block_ads_enabled)
736 easyListPreference.setIcon(R.drawable.block_ads_disabled)
739 getString(R.string.easyprivacy_key) -> {
741 if (sharedPreferences.getBoolean(getString(R.string.easyprivacy_key), true))
742 easyPrivacyPreference.setIcon(R.drawable.block_tracking_enabled)
744 easyPrivacyPreference.setIcon(R.drawable.block_tracking_disabled)
747 getString(R.string.fanboys_annoyance_list_key) -> {
748 // Get the current Fanboy settings.
749 val currentFanboyAnnoyanceList = sharedPreferences.getBoolean(getString(R.string.fanboys_annoyance_list_key), true)
750 val currentFanboySocialBlockingList = sharedPreferences.getBoolean(getString(R.string.fanboys_social_blocking_list_key), true)
752 // Update the Fanboy icons.
753 if (currentFanboyAnnoyanceList) { // Fanboy's annoyance list is enabled.
754 // Update the Fanboy's annoyance list icon.
755 fanboyAnnoyanceListPreference.setIcon(R.drawable.social_media_enabled)
757 // Update the Fanboy's social blocking list icon.
758 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_ghosted)
759 } else { // Fanboy's annoyance list is disabled.
760 // Update the Fanboy's annoyance list icon.
761 fanboyAnnoyanceListPreference.setIcon(R.drawable.social_media_disabled)
763 // Update the Fanboy's social blocking list icon.
764 if (currentFanboySocialBlockingList)
765 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_enabled)
767 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_disabled)
770 // Only enable Fanboy's social blocking list preference if Fanboy's annoyance list preference is disabled.
771 fanboySocialBlockingListPreference.isEnabled = !currentFanboyAnnoyanceList
774 getString(R.string.fanboys_social_blocking_list_key) -> {
776 if (sharedPreferences.getBoolean(getString(R.string.fanboys_social_blocking_list_key), true))
777 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_enabled)
779 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_disabled)
782 getString(R.string.ultralist_key) -> {
784 if (sharedPreferences.getBoolean(getString(R.string.ultralist_key), true))
785 ultraListPreference.setIcon(R.drawable.block_ads_enabled)
787 ultraListPreference.setIcon(R.drawable.block_ads_disabled)
790 getString(R.string.ultraprivacy_key) -> {
792 if (sharedPreferences.getBoolean(getString(R.string.ultraprivacy_key), true))
793 ultraPrivacyPreference.setIcon(R.drawable.block_tracking_enabled)
795 ultraPrivacyPreference.setIcon(R.drawable.block_tracking_disabled)
798 getString(R.string.block_all_third_party_requests_key) -> {
800 if (sharedPreferences.getBoolean(getString(R.string.block_all_third_party_requests_key), false)) {
801 blockAllThirdPartyRequestsPreference.setIcon(R.drawable.block_all_third_party_requests_enabled)
803 blockAllThirdPartyRequestsPreference.setIcon(R.drawable.block_all_third_party_requests_disabled)
807 getString(R.string.tracking_queries_key) -> {
809 if (sharedPreferences.getBoolean(getString(R.string.tracking_queries_key), true))
810 trackingQueriesPreference.setIcon(R.drawable.modify_url_enabled)
812 trackingQueriesPreference.setIcon(R.drawable.modify_url_disabled)
815 getString(R.string.amp_redirects_key) -> {
817 if (sharedPreferences.getBoolean(getString(R.string.amp_redirects_key), true))
818 ampRedirectsPreference.setIcon(R.drawable.modify_url_enabled)
820 ampRedirectsPreference.setIcon(R.drawable.modify_url_disabled)
823 getString(R.string.search_key) -> {
824 // Store the new search string.
825 val newSearchString = sharedPreferences.getString(getString(R.string.search_key), getString(R.string.search_default_value))
827 // Update the search and search custom URL preferences.
828 if (newSearchString == getString(R.string.custom_url_item)) { // A custom URL is selected.
829 // Set the summary text to `R.string.custom_url`, which is translated.
830 searchPreference.setSummary(R.string.custom_url)
832 // Enable the search custom URL preference.
833 searchCustomURLPreference.isEnabled = true
835 // Set the search custom URL preference icon.
836 searchCustomURLPreference.setIcon(R.drawable.search_custom_enabled)
837 } else { // A custom URL is not selected.
838 // Set the summary text to the new search string.
839 searchPreference.summary = newSearchString
841 // Disable the search custom URL Preference.
842 searchCustomURLPreference.isEnabled = false
844 // Set the search custom URL preference icon.
845 searchCustomURLPreference.setIcon(R.drawable.search_custom_ghosted)
849 getString(R.string.search_custom_url_key) -> {
850 // Set the new search custom URL as the summary text for the preference.
851 searchCustomURLPreference.summary = sharedPreferences.getString(getString(R.string.search_custom_url_key), getString(R.string.search_custom_url_default_value))
854 getString(R.string.proxy_key) -> {
855 // Get the current proxy string.
856 val currentProxyString = sharedPreferences.getString(getString(R.string.proxy_key), getString(R.string.proxy_default_value))
858 // Update the proxy preference summary text.
859 proxyPreference.summary = when (currentProxyString) {
860 ProxyHelper.NONE -> getString(R.string.no_proxy_enabled)
861 ProxyHelper.TOR -> getString(R.string.tor_enabled)
862 ProxyHelper.I2P -> getString(R.string.i2p_enabled)
863 ProxyHelper.CUSTOM -> getString(R.string.custom_proxy)
864 else -> getString(R.string.no_proxy_enabled)
867 // Update the status of the custom URL preference.
868 proxyCustomUrlPreference.isEnabled = currentProxyString == ProxyHelper.CUSTOM
871 if (currentProxyString == ProxyHelper.NONE) { // Proxying is disabled.
872 // Set the main proxy icon to be disabled
873 proxyPreference.setIcon(R.drawable.proxy_disabled)
875 // Set the custom proxy URL icon to be ghosted.
876 proxyCustomUrlPreference.setIcon(R.drawable.proxy_ghosted)
877 } else { // Proxying is enabled.
878 // Set the main proxy icon to be enabled.
879 proxyPreference.setIcon(R.drawable.proxy_enabled)
881 /// Set the custom proxy URL icon according to its status.
882 if (proxyCustomUrlPreference.isEnabled)
883 proxyCustomUrlPreference.setIcon(R.drawable.proxy_enabled)
885 proxyCustomUrlPreference.setIcon(R.drawable.proxy_ghosted)
889 getString(R.string.proxy_custom_url_key) -> {
890 // Set the summary text for the proxy custom URL.
891 proxyCustomUrlPreference.summary = sharedPreferences.getString(getString(R.string.proxy_custom_url_key), getString(R.string.proxy_custom_url_default_value))
894 getString(R.string.full_screen_browsing_mode_key) -> {
896 if (sharedPreferences.getBoolean(getString(R.string.full_screen_browsing_mode_key), false)) { // Full screen browsing is enabled.
897 // Set the full screen browsing mode preference icon.
898 fullScreenBrowsingModePreference.setIcon(R.drawable.full_screen_enabled)
900 // Set the hide app bar preference icon.
901 if (sharedPreferences.getBoolean(getString(R.string.hide_app_bar_key), true))
902 hideAppBarPreference.setIcon(R.drawable.app_bar_enabled)
904 hideAppBarPreference.setIcon(R.drawable.app_bar_disabled)
905 } else { // Full screen browsing is disabled.
907 fullScreenBrowsingModePreference.setIcon(R.drawable.full_screen_disabled)
908 hideAppBarPreference.setIcon(R.drawable.app_bar_ghosted)
912 getString(R.string.hide_app_bar_key) -> {
914 if (sharedPreferences.getBoolean(getString(R.string.hide_app_bar_key), true))
915 hideAppBarPreference.setIcon(R.drawable.app_bar_enabled)
917 hideAppBarPreference.setIcon(R.drawable.app_bar_disabled)
920 getString(R.string.clear_everything_key) -> {
921 // Store the new clear everything status
922 val newClearEverythingBoolean = sharedPreferences.getBoolean(getString(R.string.clear_everything_key), true)
924 // Update the status of the clear and exit preferences.
925 clearCookiesPreference.isEnabled = !newClearEverythingBoolean
926 clearDomStoragePreference.isEnabled = !newClearEverythingBoolean
927 clearFormDataPreference.isEnabled = !newClearEverythingBoolean // Clear form data can be removed once the minimum API >= 26.
928 clearLogcatPreference.isEnabled = !newClearEverythingBoolean
929 clearCachePreference.isEnabled = !newClearEverythingBoolean
931 // Update the clear everything preference icon.
932 if (newClearEverythingBoolean)
933 clearEverythingPreference.setIcon(R.drawable.clear_everything_enabled)
935 clearEverythingPreference.setIcon(R.drawable.clear_everything_disabled)
937 // Update the clear cookies preference icon.
938 if (newClearEverythingBoolean || sharedPreferences.getBoolean(getString(R.string.clear_cookies_key), true))
939 clearCookiesPreference.setIcon(R.drawable.clear_cookies_enabled)
941 clearCookiesPreference.setIcon(R.drawable.clear_cookies_disabled)
943 // Update the clear dom storage preference icon.
944 if (newClearEverythingBoolean || sharedPreferences.getBoolean(getString(R.string.clear_dom_storage_key), true))
945 clearDomStoragePreference.setIcon(R.drawable.clear_dom_storage_enabled)
947 clearDomStoragePreference.setIcon(R.drawable.clear_dom_storage_disabled)
949 // Update the clear form data preference icon if the API < 26.
950 if (Build.VERSION.SDK_INT < 26) {
951 if (newClearEverythingBoolean || sharedPreferences.getBoolean(getString(R.string.clear_form_data_key), true))
952 clearFormDataPreference.setIcon(R.drawable.clear_form_data_enabled)
954 clearFormDataPreference.setIcon(R.drawable.clear_form_data_disabled)
957 // Update the clear logcat preference icon.
958 if (newClearEverythingBoolean || sharedPreferences.getBoolean(getString(R.string.clear_logcat_key), true))
959 clearLogcatPreference.setIcon(R.drawable.clear_logcat_enabled)
961 clearLogcatPreference.setIcon(R.drawable.clear_logcat_disabled)
963 // Update the clear cache preference icon.
964 if (newClearEverythingBoolean || sharedPreferences.getBoolean(getString(R.string.clear_cache_key), true))
965 clearCachePreference.setIcon(R.drawable.clear_cache_enabled)
967 clearCachePreference.setIcon(R.drawable.clear_cache_disabled)
970 getString(R.string.clear_cookies_key) -> {
972 if (sharedPreferences.getBoolean(getString(R.string.clear_cookies_key), true))
973 clearCookiesPreference.setIcon(R.drawable.clear_cookies_enabled)
975 clearCookiesPreference.setIcon(R.drawable.clear_cookies_disabled)
978 getString(R.string.clear_dom_storage_key) -> {
980 if (sharedPreferences.getBoolean(getString(R.string.clear_dom_storage_key), true))
981 clearDomStoragePreference.setIcon(R.drawable.clear_dom_storage_enabled)
983 clearDomStoragePreference.setIcon(R.drawable.clear_dom_storage_disabled)
986 getString(R.string.clear_form_data_key) -> {
988 if (sharedPreferences.getBoolean(getString(R.string.clear_form_data_key), true))
989 clearFormDataPreference.setIcon(R.drawable.clear_form_data_enabled)
991 clearFormDataPreference.setIcon(R.drawable.clear_form_data_disabled)
994 getString(R.string.clear_logcat_key) -> {
996 if (sharedPreferences.getBoolean(getString(R.string.clear_logcat_key), true))
997 clearLogcatPreference.setIcon(R.drawable.clear_logcat_enabled)
999 clearLogcatPreference.setIcon(R.drawable.clear_logcat_disabled)
1002 getString(R.string.clear_cache_key) -> {
1004 if (sharedPreferences.getBoolean(getString(R.string.clear_cache_key), true))
1005 clearCachePreference.setIcon(R.drawable.clear_cache_enabled)
1007 clearCachePreference.setIcon(R.drawable.clear_cache_disabled)
1010 getString(R.string.homepage_key) -> {
1011 // Set the new homepage URL as the summary text for the Homepage preference.
1012 homepagePreference.summary = sharedPreferences.getString(getString(R.string.homepage_key), getString(R.string.homepage_default_value))
1015 getString(R.string.font_size_key) -> {
1016 // Update the font size summary text.
1017 fontSizePreference.summary = sharedPreferences.getString(getString(R.string.font_size_key), getString(R.string.font_size_default_value)) + "%"
1020 getString(R.string.open_intents_in_new_tab_key) -> {
1022 if (sharedPreferences.getBoolean(getString(R.string.open_intents_in_new_tab_key), true))
1023 openIntentsInNewTabPreference.setIcon(R.drawable.tab_enabled)
1025 openIntentsInNewTabPreference.setIcon(R.drawable.tab_disabled)
1028 getString(R.string.swipe_to_refresh_key) -> {
1030 if (sharedPreferences.getBoolean(getString(R.string.swipe_to_refresh_key), true))
1031 swipeToRefreshPreference.setIcon(R.drawable.refresh_enabled)
1033 swipeToRefreshPreference.setIcon(R.drawable.refresh_disabled)
1036 getString(R.string.download_with_external_app_key) -> {
1038 if (sharedPreferences.getBoolean(getString(R.string.download_with_external_app_key), false))
1039 downloadWithExternalAppPreference.setIcon(R.drawable.download_with_external_app_enabled)
1041 downloadWithExternalAppPreference.setIcon(R.drawable.download_with_external_app_disabled)
1044 getString(R.string.scroll_app_bar_key) -> {
1046 if (sharedPreferences.getBoolean(getString(R.string.scroll_app_bar_key), true))
1047 scrollAppBarPreference.setIcon(R.drawable.app_bar_enabled)
1049 scrollAppBarPreference.setIcon(R.drawable.app_bar_disabled)
1052 getString(R.string.bottom_app_bar_key) -> {
1054 if (sharedPreferences.getBoolean(getString(R.string.bottom_app_bar_key), false))
1055 bottomAppBarPreference.setIcon(R.drawable.bottom_app_bar_enabled)
1057 bottomAppBarPreference.setIcon(R.drawable.bottom_app_bar_disabled)
1059 // Restart Privacy Browser.
1060 restartPrivacyBrowser()
1063 getString(R.string.display_additional_app_bar_icons_key) -> {
1065 if (sharedPreferences.getBoolean(getString(R.string.display_additional_app_bar_icons_key), false))
1066 displayAdditionalAppBarIconsPreference.setIcon(R.drawable.more_enabled)
1068 displayAdditionalAppBarIconsPreference.setIcon(R.drawable.more_disabled)
1071 getString(R.string.app_theme_key) -> {
1072 // Get the app theme entry number that matches the current app theme. A switch statement cannot be used because the theme entry values string array is not a compile time constant.
1073 val appThemeEntryNumber: Int = when (sharedPreferences.getString(getString(R.string.app_theme_key), getString(R.string.app_theme_default_value))) {
1074 appThemeEntryValuesStringArray[1] -> 1 // The light theme is selected.
1075 appThemeEntryValuesStringArray[2] -> 2 // The dark theme is selected.
1076 else -> 0 // The system default theme is selected.
1079 // Update the system according to the new theme.
1080 when (appThemeEntryNumber) {
1081 0 -> { // The system default theme is selected.
1082 // Update the theme preference summary text.
1083 appThemePreference.summary = appThemeEntriesStringArray[0]
1085 // Apply the new theme.
1086 if (Build.VERSION.SDK_INT >= 28) { // The system default theme is supported.
1087 // Follow the system default theme.
1088 AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
1089 } else { // The system default theme is not supported.
1090 // Follow the battery saver mode.
1091 AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_AUTO_BATTERY)
1095 1 -> { // The light theme is selected.
1096 // Update the theme preference summary text.
1097 appThemePreference.summary = appThemeEntriesStringArray[1]
1099 // Apply the new theme.
1100 AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
1103 2 -> { // The dark theme is selected.
1104 // Update the theme preference summary text.
1105 appThemePreference.summary = appThemeEntriesStringArray[2]
1107 // Apply the new theme.
1108 AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
1112 // Enable the WebView theme preference if the API < 33 or the app theme is set to light.
1113 webViewThemePreference.isEnabled = ((Build.VERSION.SDK_INT < 33) || (appThemeEntryNumber != 1))
1115 // Get the webView theme entry number that matches the new WebView theme.
1116 val webViewThemeEntryNumber: Int = when (sharedPreferences.getString(getString(R.string.webview_theme_key), getString(R.string.webview_theme_default_value))) {
1117 webViewThemeEntriesStringArray[1] -> 1 // The light theme is selected.
1118 webViewThemeEntryValuesStringArray[2] -> 2 // The dark theme is selected.
1119 else -> 0 // The system default theme is selected.
1122 // Update the WebView theme icon.
1123 if (webViewThemePreference.isEnabled) { // The WebView theme preference is enabled.
1124 when (webViewThemeEntryNumber) {
1125 // The system default WebView theme is selected.
1127 // Get the current theme status.
1128 val currentThemeStatus = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
1130 // Set the icon according to the app theme.
1131 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO)
1132 webViewThemePreference.setIcon(R.drawable.webview_light_theme)
1134 webViewThemePreference.setIcon(R.drawable.webview_dark_theme)
1137 // The light WebView theme is selected.
1140 webViewThemePreference.setIcon(R.drawable.webview_light_theme)
1143 // The dark WebView theme is selected.
1146 webViewThemePreference.setIcon(R.drawable.webview_dark_theme)
1149 } else { // The WebView theme preference is disabled.
1150 webViewThemePreference.setIcon(R.drawable.webview_theme_ghosted)
1154 getString(R.string.webview_theme_key) -> {
1155 // Get the webView theme entry number that matches the new WebView theme.
1156 val newWebViewThemeEntryNumber: Int = when (sharedPreferences.getString(getString(R.string.webview_theme_key), getString(R.string.webview_theme_default_value))) {
1157 webViewThemeEntriesStringArray[1] -> 1 // The light theme is selected.
1158 webViewThemeEntryValuesStringArray[2] -> 2 // The dark theme is selected.
1159 else -> 0 // The system default theme is selected.
1162 // Update the WebView theme icon.
1163 when (newWebViewThemeEntryNumber) {
1164 // The system default WebView theme is selected.
1166 // Get the current theme status.
1167 val currentThemeStatus = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
1170 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO)
1171 webViewThemePreference.setIcon(R.drawable.webview_light_theme)
1173 webViewThemePreference.setIcon(R.drawable.webview_dark_theme)
1176 // The light WebView theme is selected.
1179 webViewThemePreference.setIcon(R.drawable.webview_light_theme)
1182 // The dark WebView theme is selected.
1185 webViewThemePreference.setIcon(R.drawable.webview_dark_theme)
1189 // Set the current theme as the summary text for the preference.
1190 webViewThemePreference.summary = webViewThemeEntriesStringArray[newWebViewThemeEntryNumber]
1193 getString(R.string.wide_viewport_key) -> {
1195 if (sharedPreferences.getBoolean(getString(R.string.wide_viewport_key), true))
1196 wideViewportPreference.setIcon(R.drawable.wide_viewport_enabled)
1198 wideViewportPreference.setIcon(R.drawable.wide_viewport_disabled)
1201 getString(R.string.display_webpage_images_key) -> {
1203 if (sharedPreferences.getBoolean(getString(R.string.display_webpage_images_key), true))
1204 displayWebpageImagesPreference.setIcon(R.drawable.images_enabled)
1206 displayWebpageImagesPreference.setIcon(R.drawable.images_disabled)
1212 private fun restartPrivacyBrowser() {
1213 // Create an intent to restart Privacy Browser.
1214 val restartIntent = requireActivity().parentActivityIntent!!
1216 // `Intent.FLAG_ACTIVITY_CLEAR_TASK` removes all activities from the stack. It requires `Intent.FLAG_ACTIVITY_NEW_TASK`.
1217 restartIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
1219 // Create a handler to restart the activity.
1220 val restartHandler = Handler(Looper.getMainLooper())
1222 // Create a runnable to restart the activity.
1223 val restartRunnable = Runnable {
1224 // Restart the activity.
1225 startActivity(restartIntent)
1227 // Kill this instance of Privacy Browser. Otherwise, the app exhibits sporadic behavior after the restart.
1231 // Restart the activity after 400 milliseconds, so that the app has enough time to save the change to the preference.
1232 restartHandler.postDelayed(restartRunnable, 400)