2 * Copyright 2016-2024 Soren Stoutner <soren@stoutner.com>.
4 * This file is part of Privacy Browser Android <https://www.stoutner.com/privacy-browser-android>.
6 * Privacy Browser Android is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * Privacy Browser Android is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with Privacy Browser Android. If not, see <http://www.gnu.org/licenses/>.
20 package com.stoutner.privacybrowser.fragments
22 import android.annotation.SuppressLint
23 import android.content.Intent
24 import android.content.SharedPreferences
25 import android.content.SharedPreferences.OnSharedPreferenceChangeListener
26 import android.content.res.Configuration
27 import android.os.Build
28 import android.os.Bundle
29 import android.os.Handler
30 import android.os.Looper
31 import android.webkit.WebView
32 import android.widget.ArrayAdapter
34 import androidx.appcompat.app.AppCompatDelegate
35 import androidx.preference.Preference
36 import androidx.preference.PreferenceFragmentCompat
38 import com.stoutner.privacybrowser.R
39 import com.stoutner.privacybrowser.activities.SETTINGS_CUSTOM_USER_AGENT
40 import com.stoutner.privacybrowser.activities.SETTINGS_WEBVIEW_DEFAULT_USER_AGENT
41 import com.stoutner.privacybrowser.activities.UNRECOGNIZED_USER_AGENT
42 import com.stoutner.privacybrowser.helpers.ProxyHelper
43 import kotlin.system.exitProcess
45 // Define the class constants.
46 private const val SCROLL_Y = "scroll_y"
48 class SettingsFragment : PreferenceFragmentCompat() {
50 // Declare the private static class variables. For some reason (I'm looking at you Android's Activity Lifecycle) this only works if these are static.
51 private var fragmentRestarted: Boolean = false
52 private var scrollY: Int = 0
55 // Declare the class variables.
56 private lateinit var allowScreenshotsPreference: Preference
57 private lateinit var ampRedirectsPreference: Preference
58 private lateinit var appThemeEntriesStringArray: Array<String>
59 private lateinit var appThemeEntryValuesStringArray: Array<String>
60 private lateinit var appThemePreference: Preference
61 private lateinit var blockAllThirdPartyRequestsPreference: Preference
62 private lateinit var bottomAppBarPreference: Preference
63 private lateinit var clearCachePreference: Preference
64 private lateinit var clearCookiesPreference: Preference
65 private lateinit var clearDomStoragePreference: Preference
66 private lateinit var clearEverythingPreference: Preference
67 private lateinit var clearLogcatPreference: Preference
68 private lateinit var cookiesPreference: Preference
69 private lateinit var customUserAgentPreference: Preference
70 private lateinit var defaultUserAgent: String
71 private lateinit var displayAdditionalAppBarIconsPreference: Preference
72 private lateinit var displayWebpageImagesPreference: Preference
73 private lateinit var domStoragePreference: Preference
74 private lateinit var downloadProviderEntryValuesStringArray: Array<String>
75 private lateinit var downloadProviderPreference: Preference
76 private lateinit var easyListPreference: Preference
77 private lateinit var easyPrivacyPreference: Preference
78 private lateinit var fanboyAnnoyanceListPreference: Preference
79 private lateinit var fanboySocialBlockingListPreference: Preference
80 private lateinit var fontSizePreference: Preference
81 private lateinit var fullScreenBrowsingModePreference: Preference
82 private lateinit var hideAppBarPreference: Preference
83 private lateinit var displayUnderCutoutsPreference: Preference
84 private lateinit var homepagePreference: Preference
85 private lateinit var incognitoModePreference: Preference
86 private lateinit var javaScriptPreference: Preference
87 private lateinit var openIntentsInNewTabPreference: Preference
88 private lateinit var proxyCustomUrlPreference: Preference
89 private lateinit var proxyPreference: Preference
90 private lateinit var scrollAppBarPreference: Preference
91 private lateinit var searchCustomURLPreference: Preference
92 private lateinit var searchPreference: Preference
93 private lateinit var sharedPreferenceChangeListener: OnSharedPreferenceChangeListener
94 private lateinit var swipeToRefreshPreference: Preference
95 private lateinit var trackingQueriesPreference: Preference
96 private lateinit var translatedUserAgentNamesArray: Array<String>
97 private lateinit var ultraListPreference: Preference
98 private lateinit var ultraPrivacyPreference: Preference
99 private lateinit var userAgentDataArray: Array<String>
100 private lateinit var userAgentPreference: Preference
101 private lateinit var userAgentNamesArray: ArrayAdapter<CharSequence>
102 private lateinit var webViewThemeEntriesStringArray: Array<String>
103 private lateinit var webViewThemeEntryValuesStringArray: Array<String>
104 private lateinit var webViewThemePreference: Preference
105 private lateinit var wideViewportPreference: Preference
107 override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
108 // Check if the fragment has been restarted.
109 if (savedInstanceState != null) {
110 // Set the fragment restored flag.
111 fragmentRestarted = true
113 // Save the scroll Y.
114 scrollY = savedInstanceState.getInt(SCROLL_Y)
117 // Load the preferences from the XML file.
118 setPreferencesFromResource(R.xml.preferences, rootKey)
120 // Get a handle for the shared preferences.
121 val sharedPreferences = preferenceScreen.sharedPreferences!!
123 // Get handles for the preferences.
124 javaScriptPreference = findPreference(getString(R.string.javascript_key))!!
125 cookiesPreference = findPreference(getString(R.string.cookies_key))!!
126 domStoragePreference = findPreference(getString(R.string.dom_storage_key))!!
127 userAgentPreference = findPreference(getString(R.string.user_agent_key))!!
128 customUserAgentPreference = findPreference(getString(R.string.custom_user_agent_key))!!
129 incognitoModePreference = findPreference(getString(R.string.incognito_mode_key))!!
130 allowScreenshotsPreference = findPreference(getString(R.string.allow_screenshots_key))!!
131 easyListPreference = findPreference(getString(R.string.easylist_key))!!
132 easyPrivacyPreference = findPreference(getString(R.string.easyprivacy_key))!!
133 fanboyAnnoyanceListPreference = findPreference(getString(R.string.fanboys_annoyance_list_key))!!
134 fanboySocialBlockingListPreference = findPreference(getString(R.string.fanboys_social_blocking_list_key))!!
135 ultraListPreference = findPreference(getString(R.string.ultralist_key))!!
136 ultraPrivacyPreference = findPreference(getString(R.string.ultraprivacy_key))!!
137 blockAllThirdPartyRequestsPreference = findPreference(getString(R.string.block_all_third_party_requests_key))!!
138 trackingQueriesPreference = findPreference(getString(R.string.tracking_queries_key))!!
139 ampRedirectsPreference = findPreference(getString(R.string.amp_redirects_key))!!
140 searchPreference = findPreference(getString(R.string.search_key))!!
141 searchCustomURLPreference = findPreference(getString(R.string.search_custom_url_key))!!
142 proxyPreference = findPreference(getString(R.string.proxy_key))!!
143 proxyCustomUrlPreference = findPreference(getString(R.string.proxy_custom_url_key))!!
144 fullScreenBrowsingModePreference = findPreference(getString(R.string.full_screen_browsing_mode_key))!!
145 hideAppBarPreference = findPreference(getString(R.string.hide_app_bar_key))!!
146 displayUnderCutoutsPreference = findPreference(getString(R.string.display_under_cutouts_key))!!
147 clearEverythingPreference = findPreference(getString(R.string.clear_everything_key))!!
148 clearCookiesPreference = findPreference(getString(R.string.clear_cookies_key))!!
149 clearDomStoragePreference = findPreference(getString(R.string.clear_dom_storage_key))!!
150 clearLogcatPreference = findPreference(getString(R.string.clear_logcat_key))!!
151 clearCachePreference = findPreference(getString(R.string.clear_cache_key))!!
152 homepagePreference = findPreference(getString(R.string.homepage_key))!!
153 fontSizePreference = findPreference(getString(R.string.font_size_key))!!
154 openIntentsInNewTabPreference = findPreference(getString(R.string.open_intents_in_new_tab_key))!!
155 swipeToRefreshPreference = findPreference(getString(R.string.swipe_to_refresh_key))!!
156 downloadProviderPreference = findPreference(getString(R.string.download_provider_key))!!
157 scrollAppBarPreference = findPreference(getString(R.string.scroll_app_bar_key))!!
158 bottomAppBarPreference = findPreference(getString(R.string.bottom_app_bar_key))!!
159 displayAdditionalAppBarIconsPreference = findPreference(getString(R.string.display_additional_app_bar_icons_key))!!
160 appThemePreference = findPreference(getString(R.string.app_theme_key))!!
161 webViewThemePreference = findPreference(getString(R.string.webview_theme_key))!!
162 wideViewportPreference = findPreference(getString(R.string.wide_viewport_key))!!
163 displayWebpageImagesPreference = findPreference(getString(R.string.display_webpage_images_key))!!
165 // Set the preference dependencies.
166 domStoragePreference.dependency = getString(R.string.javascript_key)
167 hideAppBarPreference.dependency = getString(R.string.full_screen_browsing_mode_key)
168 displayUnderCutoutsPreference.dependency = getString(R.string.full_screen_browsing_mode_key)
170 // Get strings from the preferences.
171 val userAgentName = sharedPreferences.getString(getString(R.string.user_agent_key), getString(R.string.user_agent_default_value))
172 val searchString = sharedPreferences.getString(getString(R.string.search_key), getString(R.string.search_default_value))
173 val proxyString = sharedPreferences.getString(getString(R.string.proxy_key), getString(R.string.proxy_default_value))
175 // Get booleans that are used in multiple places from the preferences.
176 val javaScriptEnabled = sharedPreferences.getBoolean(getString(R.string.javascript_key), false)
177 val fanboyAnnoyanceListEnabled = sharedPreferences.getBoolean(getString(R.string.fanboys_annoyance_list_key), true)
178 val fanboySocialBlockingEnabled = sharedPreferences.getBoolean(getString(R.string.fanboys_social_blocking_list_key), true)
179 val fullScreenBrowsingMode = sharedPreferences.getBoolean(getString(R.string.full_screen_browsing_mode_key), false)
180 val clearEverything = sharedPreferences.getBoolean(getString(R.string.clear_everything_key), true)
182 // Only enable Fanboy's social blocking list preference if Fanboy's annoyance list is disabled.
183 fanboySocialBlockingListPreference.isEnabled = !fanboyAnnoyanceListEnabled
186 // Inflate a WebView to get the default user agent.
187 val inflater = requireActivity().layoutInflater
189 // `@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.
190 @SuppressLint("InflateParams") val bareWebViewLayout = inflater.inflate(R.layout.bare_webview, null, false)
192 // Get a handle for the bare WebView.
193 val bareWebView = bareWebViewLayout.findViewById<WebView>(R.id.bare_webview)
195 // Get the default user agent.
196 defaultUserAgent = bareWebView.settings.userAgentString
198 // Get the user agent arrays.
199 userAgentNamesArray = ArrayAdapter.createFromResource(requireContext(), R.array.user_agent_names, R.layout.spinner_item)
200 translatedUserAgentNamesArray = resources.getStringArray(R.array.translated_user_agent_names)
201 userAgentDataArray = resources.getStringArray(R.array.user_agent_data)
203 // Populate the user agent summary.
204 when (val userAgentArrayPosition = userAgentNamesArray.getPosition(userAgentName)) {
205 // The user agent name is not on the canonical list.
206 // 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.
207 UNRECOGNIZED_USER_AGENT -> userAgentPreference.summary = userAgentName
209 // Get the user agent text from the webview (which changes based on the version of Android and WebView installed).
210 SETTINGS_WEBVIEW_DEFAULT_USER_AGENT -> userAgentPreference.summary = "${translatedUserAgentNamesArray[userAgentArrayPosition]}:\n$defaultUserAgent"
212 // Display the custom user agent.
213 SETTINGS_CUSTOM_USER_AGENT -> userAgentPreference.setSummary(R.string.custom_user_agent)
215 // Get the user agent summary from the user agent data array.
216 else -> userAgentPreference.summary = "${translatedUserAgentNamesArray[userAgentArrayPosition]}:\n${userAgentDataArray[userAgentArrayPosition]}"
219 // Set the summary text for the custom user agent preference.
220 customUserAgentPreference.summary = sharedPreferences.getString(getString(R.string.custom_user_agent_key), getString(R.string.custom_user_agent_default_value))
222 // Only enable the custom user agent preference if the user agent is set to custom.
223 customUserAgentPreference.isEnabled = (userAgentPreference.summary == getString(R.string.custom_user_agent))
225 // Set the search URL as the summary text for the search preference when the preference screen is loaded.
226 if (searchString == getString(R.string.custom_url_item)) {
227 // Use R.string.custom_url, which will be translated, instead of the array value, which will not.
228 searchPreference.setSummary(R.string.custom_url)
230 // Set the array value as the summary text.
231 searchPreference.summary = searchString
234 // Set the summary text for the search custom URL (the default is `""`).
235 searchCustomURLPreference.summary = sharedPreferences.getString(getString(R.string.search_custom_url_key), getString(R.string.search_custom_url_default_value))
237 // Only enable the search custom URL preference if the search is set to a custom URL.
238 searchCustomURLPreference.isEnabled = (searchString == getString(R.string.custom_url_item))
240 // Set the summary text for the proxy preference.
241 proxyPreference.summary = when (proxyString) {
242 ProxyHelper.NONE -> getString(R.string.no_proxy_enabled)
243 ProxyHelper.TOR -> getString(R.string.tor_enabled)
244 ProxyHelper.I2P -> getString(R.string.i2p_enabled)
245 ProxyHelper.CUSTOM -> getString(R.string.custom_proxy)
246 else -> getString(R.string.no_proxy_enabled)
249 // Set the summary text for the custom proxy URL.
250 proxyCustomUrlPreference.summary = sharedPreferences.getString(getString(R.string.proxy_custom_url_key), getString(R.string.proxy_custom_url_default_value))
252 // Only enable the custom proxy URL if a custom proxy is selected.
253 proxyCustomUrlPreference.isEnabled = proxyString == ProxyHelper.CUSTOM
255 // Set the status of the clear and exit preferences.
256 clearCookiesPreference.isEnabled = !clearEverything
257 clearDomStoragePreference.isEnabled = !clearEverything
258 clearLogcatPreference.isEnabled = !clearEverything
259 clearCachePreference.isEnabled = !clearEverything
261 // Set the homepage URL as the summary text for the homepage preference.
262 homepagePreference.summary = sharedPreferences.getString(getString(R.string.homepage_key), getString(R.string.homepage_default_value))
264 // Set the font size as the summary text for the preference.
265 fontSizePreference.summary = sharedPreferences.getString(getString(R.string.font_size_key), getString(R.string.font_size_default_value)) + "%"
267 // Get the download provider entry values string array
268 downloadProviderEntryValuesStringArray = resources.getStringArray(R.array.download_provider_entry_values)
270 // Set the summary text for the download provider preference.
271 downloadProviderPreference.summary = when (sharedPreferences.getString(getString(R.string.download_provider_key), getString(R.string.download_provider_default_value))) {
272 downloadProviderEntryValuesStringArray[0] -> getString(R.string.download_with_privacy_browser) // Privacy Browser is selected.
273 downloadProviderEntryValuesStringArray[1] -> getString(R.string.download_with_android_download_manager) // Android download manager is selected.
274 else -> getString(R.string.download_with_external_app) // External app is selected.
277 // Get the app theme string arrays.
278 appThemeEntriesStringArray = resources.getStringArray(R.array.app_theme_entries)
279 appThemeEntryValuesStringArray = resources.getStringArray(R.array.app_theme_entry_values)
281 // Get the app theme entry number that matches the current app theme.
282 val appThemeEntryNumber: Int = when (sharedPreferences.getString(getString(R.string.app_theme_key), getString(R.string.app_theme_default_value))) {
283 appThemeEntryValuesStringArray[1] -> 1 // The light theme is selected.
284 appThemeEntryValuesStringArray[2] -> 2 // The dark theme is selected.
285 else -> 0 // The system default theme is selected.
288 // Set the current theme as the summary text for the preference.
289 appThemePreference.summary = appThemeEntriesStringArray[appThemeEntryNumber]
291 // Enable the WebView theme preference if the app theme is not set to light. Google does not allow light themes to display dark WebViews.
292 webViewThemePreference.isEnabled = (appThemeEntryNumber != 1)
294 // Get the WebView theme string arrays.
295 webViewThemeEntriesStringArray = resources.getStringArray(R.array.webview_theme_entries)
296 webViewThemeEntryValuesStringArray = resources.getStringArray(R.array.webview_theme_entry_values)
298 // Get the WebView theme entry number that matches the current WebView theme.
299 val webViewThemeEntryNumber: Int = when (sharedPreferences.getString(getString(R.string.webview_theme_key), getString(R.string.webview_theme_default_value))) {
300 webViewThemeEntryValuesStringArray[1] -> 1 // The light theme is selected.
301 webViewThemeEntryValuesStringArray[2] -> 2 // The dark theme is selected.
302 else -> 0 // The system default theme is selected.
305 // Set the current theme as the summary text for the preference.
306 webViewThemePreference.summary = webViewThemeEntriesStringArray[webViewThemeEntryNumber]
308 // Set the JavaScript icon.
309 if (javaScriptEnabled)
310 javaScriptPreference.setIcon(R.drawable.javascript_enabled)
312 javaScriptPreference.setIcon(R.drawable.privacy_mode)
314 // Set the cookies icon.
315 if (sharedPreferences.getBoolean(getString(R.string.cookies_key), false))
316 cookiesPreference.setIcon(R.drawable.cookies_enabled)
318 cookiesPreference.setIcon(R.drawable.cookies_disabled)
320 // Set the DOM storage icon.
321 if (javaScriptEnabled) { // JavaScript is enabled.
322 if (sharedPreferences.getBoolean(getString(R.string.dom_storage_key), false)) // DOM storage is enabled.
323 domStoragePreference.setIcon(R.drawable.dom_storage_enabled)
324 else // DOM storage is disabled.
325 domStoragePreference.setIcon(R.drawable.dom_storage_disabled)
326 } else { // JavaScript is disabled. DOM storage should be ghosted.
327 domStoragePreference.setIcon(R.drawable.dom_storage_ghosted)
330 // Set the custom user agent icon.
331 if (customUserAgentPreference.isEnabled)
332 customUserAgentPreference.setIcon(R.drawable.custom_user_agent_enabled)
334 customUserAgentPreference.setIcon(R.drawable.custom_user_agent_ghosted)
336 // Set the incognito mode icon.
337 if (sharedPreferences.getBoolean(getString(R.string.incognito_mode_key), false))
338 incognitoModePreference.setIcon(R.drawable.incognito_mode_enabled)
340 incognitoModePreference.setIcon(R.drawable.incognito_mode_disabled)
342 // Set the allow screenshots icon.
343 if (sharedPreferences.getBoolean(getString(R.string.allow_screenshots_key), false))
344 allowScreenshotsPreference.setIcon(R.drawable.allow_screenshots_enabled)
346 allowScreenshotsPreference.setIcon(R.drawable.allow_screenshots_disabled)
348 // Set the EasyList icon.
349 if (sharedPreferences.getBoolean(getString(R.string.easylist_key), true))
350 easyListPreference.setIcon(R.drawable.block_ads_enabled)
352 easyListPreference.setIcon(R.drawable.block_ads_disabled)
354 // Set the EasyPrivacy icon.
355 if (sharedPreferences.getBoolean(getString(R.string.easyprivacy_key), true))
356 easyPrivacyPreference.setIcon(R.drawable.block_tracking_enabled)
358 easyPrivacyPreference.setIcon(R.drawable.block_tracking_disabled)
360 // Set the Fanboy lists icons.
361 if (fanboyAnnoyanceListEnabled) {
362 // Set the Fanboy annoyance list icon.
363 fanboyAnnoyanceListPreference.setIcon(R.drawable.social_media_enabled)
365 // Set the Fanboy social blocking list icon.
366 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_ghosted)
368 // Set the Fanboy annoyance list icon.
369 fanboyAnnoyanceListPreference.setIcon(R.drawable.social_media_disabled)
371 // Set the Fanboy social blocking list icon.
372 if (fanboySocialBlockingEnabled)
373 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_enabled)
375 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_disabled)
378 // Set the UltraList icon.
379 if (sharedPreferences.getBoolean(getString(R.string.ultralist_key), true))
380 ultraListPreference.setIcon(R.drawable.block_ads_enabled)
382 ultraListPreference.setIcon(R.drawable.block_ads_disabled)
384 // Set the UltraPrivacy icon.
385 if (sharedPreferences.getBoolean(getString(R.string.ultraprivacy_key), true))
386 ultraPrivacyPreference.setIcon(R.drawable.block_tracking_enabled)
388 ultraPrivacyPreference.setIcon(R.drawable.block_tracking_disabled)
390 // Set the block all third-party requests icon.
391 if (sharedPreferences.getBoolean(getString(R.string.block_all_third_party_requests), false))
392 blockAllThirdPartyRequestsPreference.setIcon(R.drawable.block_all_third_party_requests_enabled)
394 blockAllThirdPartyRequestsPreference.setIcon(R.drawable.block_all_third_party_requests_disabled)
396 // Set the Tracking Queries icon.
397 if (sharedPreferences.getBoolean(getString(R.string.tracking_queries_key), true))
398 trackingQueriesPreference.setIcon(R.drawable.modify_url_enabled)
400 trackingQueriesPreference.setIcon(R.drawable.modify_url_disabled)
402 // Set the AMP Redirects icon.
403 if (sharedPreferences.getBoolean(getString(R.string.amp_redirects_key), true))
404 ampRedirectsPreference.setIcon(R.drawable.modify_url_enabled)
406 ampRedirectsPreference.setIcon(R.drawable.modify_url_disabled)
408 // Set the search custom URL icon.
409 if (searchCustomURLPreference.isEnabled)
410 searchCustomURLPreference.setIcon(R.drawable.search_custom_enabled)
412 searchCustomURLPreference.setIcon(R.drawable.search_custom_ghosted)
414 // Set the proxy icons according to the theme and status.
415 if (proxyString == ProxyHelper.NONE) { // Proxying is disabled.
416 // Set the main proxy icon to be disabled.
417 proxyPreference.setIcon(R.drawable.proxy_disabled)
419 // Set the custom proxy URL icon to be ghosted.
420 proxyCustomUrlPreference.setIcon(R.drawable.proxy_ghosted)
421 } else { // Proxying is enabled.
422 // Set the main proxy icon to be enabled.
423 proxyPreference.setIcon(R.drawable.proxy_enabled)
425 // Set the custom proxy URL icon according to its status.
426 if (proxyCustomUrlPreference.isEnabled)
427 proxyCustomUrlPreference.setIcon(R.drawable.proxy_enabled)
429 proxyCustomUrlPreference.setIcon(R.drawable.proxy_ghosted)
432 // Set the full-screen browsing mode icons.
433 if (fullScreenBrowsingMode) { // Full-screen browsing mode is enabled.
434 // Set the full screen browsing mode preference icon.
435 fullScreenBrowsingModePreference.setIcon(R.drawable.full_screen_enabled)
437 // Set the hide app bar icon.
438 if (sharedPreferences.getBoolean(getString(R.string.hide_app_bar_key), true))
439 hideAppBarPreference.setIcon(R.drawable.app_bar_enabled)
441 hideAppBarPreference.setIcon(R.drawable.app_bar_disabled)
442 } else { // Full screen browsing mode is disabled.
444 fullScreenBrowsingModePreference.setIcon(R.drawable.full_screen_disabled)
445 hideAppBarPreference.setIcon(R.drawable.app_bar_ghosted)
448 // Set the display under cutouts icon.
449 if (sharedPreferences.getBoolean(getString(R.string.display_under_cutouts_key), false))
450 displayUnderCutoutsPreference.setIcon(R.drawable.display_under_cutouts_enabled)
452 displayUnderCutoutsPreference.setIcon(R.drawable.display_under_cutouts_disabled)
454 // Set the clear everything icon.
455 if (clearEverything) {
456 clearEverythingPreference.setIcon(R.drawable.clear_everything_enabled)
458 clearEverythingPreference.setIcon(R.drawable.clear_everything_disabled)
461 // Set the clear cookies icon.
462 if (clearEverything || sharedPreferences.getBoolean(getString(R.string.clear_cookies_key), true))
463 clearCookiesPreference.setIcon(R.drawable.clear_cookies_enabled)
465 clearCookiesPreference.setIcon(R.drawable.clear_cookies_disabled)
467 // Set the clear DOM storage icon.
468 if (clearEverything || sharedPreferences.getBoolean(getString(R.string.clear_dom_storage_key), true))
469 clearDomStoragePreference.setIcon(R.drawable.clear_dom_storage_enabled)
471 clearDomStoragePreference.setIcon(R.drawable.clear_dom_storage_disabled)
473 // Set the clear logcat icon.
474 if (clearEverything || sharedPreferences.getBoolean(getString(R.string.clear_logcat_key), true))
475 clearLogcatPreference.setIcon(R.drawable.clear_logcat_enabled)
477 clearLogcatPreference.setIcon(R.drawable.clear_logcat_disabled)
479 // Set the clear cache icon.
480 if (clearEverything || sharedPreferences.getBoolean(getString(R.string.clear_cache_key), true))
481 clearCachePreference.setIcon(R.drawable.clear_cache_enabled)
483 clearCachePreference.setIcon(R.drawable.clear_cache_disabled)
485 // Set the open intents in new tab icon.
486 if (sharedPreferences.getBoolean(getString(R.string.open_intents_in_new_tab_key), true))
487 openIntentsInNewTabPreference.setIcon(R.drawable.tab_enabled)
489 openIntentsInNewTabPreference.setIcon(R.drawable.tab_disabled)
491 // Set the swipe to refresh icon.
492 if (sharedPreferences.getBoolean(getString(R.string.swipe_to_refresh_key), true))
493 swipeToRefreshPreference.setIcon(R.drawable.refresh_enabled)
495 swipeToRefreshPreference.setIcon(R.drawable.refresh_disabled)
497 // Set the scroll app bar icon.
498 if (sharedPreferences.getBoolean(getString(R.string.scroll_app_bar_key), false))
499 scrollAppBarPreference.setIcon(R.drawable.app_bar_enabled)
501 scrollAppBarPreference.setIcon(R.drawable.app_bar_disabled)
503 // Set the bottom app bar icon.
504 if (sharedPreferences.getBoolean(getString(R.string.bottom_app_bar_key), false))
505 bottomAppBarPreference.setIcon(R.drawable.bottom_app_bar_enabled)
507 bottomAppBarPreference.setIcon(R.drawable.bottom_app_bar_disabled)
509 // Set the display additional app bar icons icon.
510 if (sharedPreferences.getBoolean(getString(R.string.display_additional_app_bar_icons_key), false))
511 displayAdditionalAppBarIconsPreference.setIcon(R.drawable.more_enabled)
513 displayAdditionalAppBarIconsPreference.setIcon(R.drawable.more_disabled)
515 // Set the WebView theme icon.
516 if (webViewThemePreference.isEnabled) { // The WebView theme preference is enabled.
517 when (webViewThemeEntryNumber) {
518 // The system default WebView theme is selected.
520 // Get the current theme status.
521 val currentThemeStatus = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
523 // Set the icon according to the app theme.
524 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO)
525 webViewThemePreference.setIcon(R.drawable.webview_light_theme)
527 webViewThemePreference.setIcon(R.drawable.webview_dark_theme)
530 // The light WebView theme is selected.
533 webViewThemePreference.setIcon(R.drawable.webview_light_theme)
536 // The dark WebView theme is selected.
539 webViewThemePreference.setIcon(R.drawable.webview_dark_theme)
542 } else { // The WebView theme preference is disabled.
543 webViewThemePreference.setIcon(R.drawable.webview_theme_ghosted)
546 // Set the wide viewport icon.
547 if (sharedPreferences.getBoolean(getString(R.string.wide_viewport_key), true))
548 wideViewportPreference.setIcon(R.drawable.wide_viewport_enabled)
550 wideViewportPreference.setIcon(R.drawable.wide_viewport_disabled)
552 // Set the display webpage images icon.
553 if (sharedPreferences.getBoolean(getString(R.string.display_webpage_images_key), true))
554 displayWebpageImagesPreference.setIcon(R.drawable.images_enabled)
556 displayWebpageImagesPreference.setIcon(R.drawable.images_disabled)
559 // The listener should be unregistered when the app is paused.
560 override fun onPause() {
561 // Run the default commands.
564 // Get a handle for the shared preferences.
565 val sharedPreferences = preferenceScreen.sharedPreferences!!
567 // Unregister the shared preference listener.
568 sharedPreferences.unregisterOnSharedPreferenceChangeListener(sharedPreferenceChangeListener)
571 // The listener should be re-registered when the app is resumed.
572 override fun onResume() {
573 // Run the default commands.
576 // Get a new shared preference change listener.
577 sharedPreferenceChangeListener = getSharedPreferenceChangeListener()
579 // Get a handle for the shared preferences.
580 val sharedPreferences = preferenceScreen.sharedPreferences!!
582 // Re-register the shared preference listener.
583 sharedPreferences.registerOnSharedPreferenceChangeListener(sharedPreferenceChangeListener)
585 // Restore the scroll position if the fragment has been restarted.
586 if (fragmentRestarted) {
587 // Reset the fragment restarted flag.
588 fragmentRestarted = false
590 // Set the scroll position.
591 listView.post { listView.smoothScrollBy(0, scrollY) }
595 override fun onSaveInstanceState(savedInstanceState: Bundle) {
596 // Run the default commands.
597 super.onSaveInstanceState(savedInstanceState)
599 // Save the scroll position.
600 savedInstanceState.putInt(SCROLL_Y, listView.computeVerticalScrollOffset())
603 private fun getSharedPreferenceChangeListener(): OnSharedPreferenceChangeListener {
604 // Return the shared preference change listener.
605 return OnSharedPreferenceChangeListener { sharedPreferences: SharedPreferences, key: String? ->
607 getString(R.string.javascript_key) -> {
608 // Update the icons and the DOM storage preference status.
609 if (sharedPreferences.getBoolean(getString(R.string.javascript_key), false)) { // The JavaScript preference is enabled.
610 // Update the icon for the JavaScript preference.
611 javaScriptPreference.setIcon(R.drawable.javascript_enabled)
613 // Update the status of the DOM storage preference.
614 domStoragePreference.isEnabled = true
616 // Update the icon for the DOM storage preference.
617 if (sharedPreferences.getBoolean(getString(R.string.dom_storage_key), false))
618 domStoragePreference.setIcon(R.drawable.dom_storage_enabled)
620 domStoragePreference.setIcon(R.drawable.dom_storage_disabled)
621 } else { // The JavaScript preference is disabled.
622 // Update the icon for the JavaScript preference.
623 javaScriptPreference.setIcon(R.drawable.privacy_mode)
625 // Update the status of the DOM storage preference.
626 domStoragePreference.isEnabled = false
628 // Set the icon for DOM storage preference to be ghosted.
629 domStoragePreference.setIcon(R.drawable.dom_storage_ghosted)
633 getString(R.string.cookies_key) -> {
635 if (sharedPreferences.getBoolean(getString(R.string.cookies_key), false))
636 cookiesPreference.setIcon(R.drawable.cookies_enabled)
638 cookiesPreference.setIcon(R.drawable.cookies_disabled)
641 getString(R.string.dom_storage_key) -> {
643 if (sharedPreferences.getBoolean(getString(R.string.dom_storage_key), false))
644 domStoragePreference.setIcon(R.drawable.dom_storage_enabled)
646 domStoragePreference.setIcon(R.drawable.dom_storage_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 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 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.incognito_mode_key) -> {
703 if (sharedPreferences.getBoolean(getString(R.string.incognito_mode_key), false))
704 incognitoModePreference.setIcon(R.drawable.incognito_mode_enabled)
706 incognitoModePreference.setIcon(R.drawable.incognito_mode_disabled)
709 getString(R.string.allow_screenshots_key) -> {
711 if (sharedPreferences.getBoolean(getString(R.string.allow_screenshots_key), false))
712 allowScreenshotsPreference.setIcon(R.drawable.allow_screenshots_enabled)
714 allowScreenshotsPreference.setIcon(R.drawable.allow_screenshots_disabled)
716 // Restart Privacy Browser.
717 restartPrivacyBrowser()
720 getString(R.string.easylist_key) -> {
722 if (sharedPreferences.getBoolean(getString(R.string.easylist_key), true))
723 easyListPreference.setIcon(R.drawable.block_ads_enabled)
725 easyListPreference.setIcon(R.drawable.block_ads_disabled)
728 getString(R.string.easyprivacy_key) -> {
730 if (sharedPreferences.getBoolean(getString(R.string.easyprivacy_key), true))
731 easyPrivacyPreference.setIcon(R.drawable.block_tracking_enabled)
733 easyPrivacyPreference.setIcon(R.drawable.block_tracking_disabled)
736 getString(R.string.fanboys_annoyance_list_key) -> {
737 // Get the current Fanboy settings.
738 val currentFanboyAnnoyanceList = sharedPreferences.getBoolean(getString(R.string.fanboys_annoyance_list_key), true)
739 val currentFanboySocialBlockingList = sharedPreferences.getBoolean(getString(R.string.fanboys_social_blocking_list_key), true)
741 // Update the Fanboy icons.
742 if (currentFanboyAnnoyanceList) { // Fanboy's annoyance list is enabled.
743 // Update the Fanboy's annoyance list icon.
744 fanboyAnnoyanceListPreference.setIcon(R.drawable.social_media_enabled)
746 // Update the Fanboy's social blocking list icon.
747 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_ghosted)
748 } else { // Fanboy's annoyance list is disabled.
749 // Update the Fanboy's annoyance list icon.
750 fanboyAnnoyanceListPreference.setIcon(R.drawable.social_media_disabled)
752 // Update the Fanboy's social blocking list icon.
753 if (currentFanboySocialBlockingList)
754 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_enabled)
756 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_disabled)
759 // Only enable Fanboy's social blocking list preference if Fanboy's annoyance list preference is disabled.
760 fanboySocialBlockingListPreference.isEnabled = !currentFanboyAnnoyanceList
763 getString(R.string.fanboys_social_blocking_list_key) -> {
765 if (sharedPreferences.getBoolean(getString(R.string.fanboys_social_blocking_list_key), true))
766 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_enabled)
768 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_disabled)
771 getString(R.string.ultralist_key) -> {
773 if (sharedPreferences.getBoolean(getString(R.string.ultralist_key), true))
774 ultraListPreference.setIcon(R.drawable.block_ads_enabled)
776 ultraListPreference.setIcon(R.drawable.block_ads_disabled)
779 getString(R.string.ultraprivacy_key) -> {
781 if (sharedPreferences.getBoolean(getString(R.string.ultraprivacy_key), true))
782 ultraPrivacyPreference.setIcon(R.drawable.block_tracking_enabled)
784 ultraPrivacyPreference.setIcon(R.drawable.block_tracking_disabled)
787 getString(R.string.block_all_third_party_requests_key) -> {
789 if (sharedPreferences.getBoolean(getString(R.string.block_all_third_party_requests_key), false)) {
790 blockAllThirdPartyRequestsPreference.setIcon(R.drawable.block_all_third_party_requests_enabled)
792 blockAllThirdPartyRequestsPreference.setIcon(R.drawable.block_all_third_party_requests_disabled)
796 getString(R.string.tracking_queries_key) -> {
798 if (sharedPreferences.getBoolean(getString(R.string.tracking_queries_key), true))
799 trackingQueriesPreference.setIcon(R.drawable.modify_url_enabled)
801 trackingQueriesPreference.setIcon(R.drawable.modify_url_disabled)
804 getString(R.string.amp_redirects_key) -> {
806 if (sharedPreferences.getBoolean(getString(R.string.amp_redirects_key), true))
807 ampRedirectsPreference.setIcon(R.drawable.modify_url_enabled)
809 ampRedirectsPreference.setIcon(R.drawable.modify_url_disabled)
812 getString(R.string.search_key) -> {
813 // Store the new search string.
814 val newSearchString = sharedPreferences.getString(getString(R.string.search_key), getString(R.string.search_default_value))
816 // Update the search and search custom URL preferences.
817 if (newSearchString == getString(R.string.custom_url_item)) { // A custom URL is selected.
818 // Set the summary text to `R.string.custom_url`, which is translated.
819 searchPreference.setSummary(R.string.custom_url)
821 // Enable the search custom URL preference.
822 searchCustomURLPreference.isEnabled = true
824 // Set the search custom URL preference icon.
825 searchCustomURLPreference.setIcon(R.drawable.search_custom_enabled)
826 } else { // A custom URL is not selected.
827 // Set the summary text to the new search string.
828 searchPreference.summary = newSearchString
830 // Disable the search custom URL Preference.
831 searchCustomURLPreference.isEnabled = false
833 // Set the search custom URL preference icon.
834 searchCustomURLPreference.setIcon(R.drawable.search_custom_ghosted)
838 getString(R.string.search_custom_url_key) -> {
839 // Set the new search custom URL as the summary text for the preference.
840 searchCustomURLPreference.summary = sharedPreferences.getString(getString(R.string.search_custom_url_key), getString(R.string.search_custom_url_default_value))
843 getString(R.string.proxy_key) -> {
844 // Get the current proxy string.
845 val currentProxyString = sharedPreferences.getString(getString(R.string.proxy_key), getString(R.string.proxy_default_value))
847 // Update the proxy preference summary text.
848 proxyPreference.summary = when (currentProxyString) {
849 ProxyHelper.NONE -> getString(R.string.no_proxy_enabled)
850 ProxyHelper.TOR -> getString(R.string.tor_enabled)
851 ProxyHelper.I2P -> getString(R.string.i2p_enabled)
852 ProxyHelper.CUSTOM -> getString(R.string.custom_proxy)
853 else -> getString(R.string.no_proxy_enabled)
856 // Update the status of the custom URL preference.
857 proxyCustomUrlPreference.isEnabled = currentProxyString == ProxyHelper.CUSTOM
860 if (currentProxyString == ProxyHelper.NONE) { // Proxying is disabled.
861 // Set the main proxy icon to be disabled
862 proxyPreference.setIcon(R.drawable.proxy_disabled)
864 // Set the custom proxy URL icon to be ghosted.
865 proxyCustomUrlPreference.setIcon(R.drawable.proxy_ghosted)
866 } else { // Proxying is enabled.
867 // Set the main proxy icon to be enabled.
868 proxyPreference.setIcon(R.drawable.proxy_enabled)
870 /// Set the custom proxy URL icon according to its status.
871 if (proxyCustomUrlPreference.isEnabled)
872 proxyCustomUrlPreference.setIcon(R.drawable.proxy_enabled)
874 proxyCustomUrlPreference.setIcon(R.drawable.proxy_ghosted)
878 getString(R.string.proxy_custom_url_key) -> {
879 // Set the summary text for the proxy custom URL.
880 proxyCustomUrlPreference.summary = sharedPreferences.getString(getString(R.string.proxy_custom_url_key), getString(R.string.proxy_custom_url_default_value))
883 getString(R.string.full_screen_browsing_mode_key) -> {
885 if (sharedPreferences.getBoolean(getString(R.string.full_screen_browsing_mode_key), false)) { // Full screen browsing is enabled.
886 // Set the full screen browsing mode preference icon.
887 fullScreenBrowsingModePreference.setIcon(R.drawable.full_screen_enabled)
889 // Set the hide app bar preference icon.
890 if (sharedPreferences.getBoolean(getString(R.string.hide_app_bar_key), true))
891 hideAppBarPreference.setIcon(R.drawable.app_bar_enabled)
893 hideAppBarPreference.setIcon(R.drawable.app_bar_disabled)
894 } else { // Full screen browsing is disabled.
896 fullScreenBrowsingModePreference.setIcon(R.drawable.full_screen_disabled)
897 hideAppBarPreference.setIcon(R.drawable.app_bar_ghosted)
901 getString(R.string.hide_app_bar_key) -> {
903 if (sharedPreferences.getBoolean(getString(R.string.hide_app_bar_key), true))
904 hideAppBarPreference.setIcon(R.drawable.app_bar_enabled)
906 hideAppBarPreference.setIcon(R.drawable.app_bar_disabled)
909 getString(R.string.display_under_cutouts_key) -> {
911 if (sharedPreferences.getBoolean(getString(R.string.display_under_cutouts_key), true))
912 displayUnderCutoutsPreference.setIcon(R.drawable.display_under_cutouts_enabled)
914 displayUnderCutoutsPreference.setIcon(R.drawable.display_under_cutouts_disabled)
916 // Restart Privacy Browser.
917 restartPrivacyBrowser()
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 clearLogcatPreference.isEnabled = !newClearEverythingBoolean
928 clearCachePreference.isEnabled = !newClearEverythingBoolean
930 // Update the clear everything preference icon.
931 if (newClearEverythingBoolean)
932 clearEverythingPreference.setIcon(R.drawable.clear_everything_enabled)
934 clearEverythingPreference.setIcon(R.drawable.clear_everything_disabled)
936 // Update the clear cookies preference icon.
937 if (newClearEverythingBoolean || sharedPreferences.getBoolean(getString(R.string.clear_cookies_key), true))
938 clearCookiesPreference.setIcon(R.drawable.clear_cookies_enabled)
940 clearCookiesPreference.setIcon(R.drawable.clear_cookies_disabled)
942 // Update the clear dom storage preference icon.
943 if (newClearEverythingBoolean || sharedPreferences.getBoolean(getString(R.string.clear_dom_storage_key), true))
944 clearDomStoragePreference.setIcon(R.drawable.clear_dom_storage_enabled)
946 clearDomStoragePreference.setIcon(R.drawable.clear_dom_storage_disabled)
948 // Update the clear logcat preference icon.
949 if (newClearEverythingBoolean || sharedPreferences.getBoolean(getString(R.string.clear_logcat_key), true))
950 clearLogcatPreference.setIcon(R.drawable.clear_logcat_enabled)
952 clearLogcatPreference.setIcon(R.drawable.clear_logcat_disabled)
954 // Update the clear cache preference icon.
955 if (newClearEverythingBoolean || sharedPreferences.getBoolean(getString(R.string.clear_cache_key), true))
956 clearCachePreference.setIcon(R.drawable.clear_cache_enabled)
958 clearCachePreference.setIcon(R.drawable.clear_cache_disabled)
961 getString(R.string.clear_cookies_key) -> {
963 if (sharedPreferences.getBoolean(getString(R.string.clear_cookies_key), true))
964 clearCookiesPreference.setIcon(R.drawable.clear_cookies_enabled)
966 clearCookiesPreference.setIcon(R.drawable.clear_cookies_disabled)
969 getString(R.string.clear_dom_storage_key) -> {
971 if (sharedPreferences.getBoolean(getString(R.string.clear_dom_storage_key), true))
972 clearDomStoragePreference.setIcon(R.drawable.clear_dom_storage_enabled)
974 clearDomStoragePreference.setIcon(R.drawable.clear_dom_storage_disabled)
977 getString(R.string.clear_logcat_key) -> {
979 if (sharedPreferences.getBoolean(getString(R.string.clear_logcat_key), true))
980 clearLogcatPreference.setIcon(R.drawable.clear_logcat_enabled)
982 clearLogcatPreference.setIcon(R.drawable.clear_logcat_disabled)
985 getString(R.string.clear_cache_key) -> {
987 if (sharedPreferences.getBoolean(getString(R.string.clear_cache_key), true))
988 clearCachePreference.setIcon(R.drawable.clear_cache_enabled)
990 clearCachePreference.setIcon(R.drawable.clear_cache_disabled)
993 getString(R.string.homepage_key) -> {
994 // Set the new homepage URL as the summary text for the Homepage preference.
995 homepagePreference.summary = sharedPreferences.getString(getString(R.string.homepage_key), getString(R.string.homepage_default_value))
998 getString(R.string.font_size_key) -> {
999 // Update the font size summary text.
1000 fontSizePreference.summary = sharedPreferences.getString(getString(R.string.font_size_key), getString(R.string.font_size_default_value)) + "%"
1003 getString(R.string.open_intents_in_new_tab_key) -> {
1005 if (sharedPreferences.getBoolean(getString(R.string.open_intents_in_new_tab_key), true))
1006 openIntentsInNewTabPreference.setIcon(R.drawable.tab_enabled)
1008 openIntentsInNewTabPreference.setIcon(R.drawable.tab_disabled)
1011 getString(R.string.swipe_to_refresh_key) -> {
1013 if (sharedPreferences.getBoolean(getString(R.string.swipe_to_refresh_key), true))
1014 swipeToRefreshPreference.setIcon(R.drawable.refresh_enabled)
1016 swipeToRefreshPreference.setIcon(R.drawable.refresh_disabled)
1019 getString(R.string.download_provider_key) -> {
1020 // Set the summary text for the download provider preference.
1021 downloadProviderPreference.summary = when (sharedPreferences.getString(getString(R.string.download_provider_key), getString(R.string.download_provider_default_value))) {
1022 downloadProviderEntryValuesStringArray[0] -> getString(R.string.download_with_privacy_browser) // Privacy Browser is selected.
1023 downloadProviderEntryValuesStringArray[1] -> getString(R.string.download_with_android_download_manager) // Android download manager is selected.
1024 else -> getString(R.string.download_with_external_app) // External app is selected.
1028 getString(R.string.scroll_app_bar_key) -> {
1030 if (sharedPreferences.getBoolean(getString(R.string.scroll_app_bar_key), false))
1031 scrollAppBarPreference.setIcon(R.drawable.app_bar_enabled)
1033 scrollAppBarPreference.setIcon(R.drawable.app_bar_disabled)
1036 getString(R.string.bottom_app_bar_key) -> {
1038 if (sharedPreferences.getBoolean(getString(R.string.bottom_app_bar_key), false))
1039 bottomAppBarPreference.setIcon(R.drawable.bottom_app_bar_enabled)
1041 bottomAppBarPreference.setIcon(R.drawable.bottom_app_bar_disabled)
1043 // Restart Privacy Browser.
1044 restartPrivacyBrowser()
1047 getString(R.string.display_additional_app_bar_icons_key) -> {
1049 if (sharedPreferences.getBoolean(getString(R.string.display_additional_app_bar_icons_key), false))
1050 displayAdditionalAppBarIconsPreference.setIcon(R.drawable.more_enabled)
1052 displayAdditionalAppBarIconsPreference.setIcon(R.drawable.more_disabled)
1054 // Restart Privacy Browser.
1055 restartPrivacyBrowser()
1058 getString(R.string.app_theme_key) -> {
1059 // Get the app theme entry number that matches the current app theme.
1060 val appThemeEntryNumber: Int = when (sharedPreferences.getString(getString(R.string.app_theme_key), getString(R.string.app_theme_default_value))) {
1061 appThemeEntryValuesStringArray[1] -> 1 // The light theme is selected.
1062 appThemeEntryValuesStringArray[2] -> 2 // The dark theme is selected.
1063 else -> 0 // The system default theme is selected.
1066 // Update the system according to the new theme.
1067 when (appThemeEntryNumber) {
1068 0 -> { // The system default theme is selected.
1069 // Update the theme preference summary text.
1070 appThemePreference.summary = appThemeEntriesStringArray[0]
1072 // Apply the new theme.
1073 if (Build.VERSION.SDK_INT >= 28) { // The system default theme is supported.
1074 // Follow the system default theme.
1075 AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
1076 } else { // The system default theme is not supported.
1077 // Follow the battery saver mode.
1078 AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_AUTO_BATTERY)
1082 1 -> { // The light theme is selected.
1083 // Update the theme preference summary text.
1084 appThemePreference.summary = appThemeEntriesStringArray[1]
1086 // Apply the new theme.
1087 AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
1090 2 -> { // The dark theme is selected.
1091 // Update the theme preference summary text.
1092 appThemePreference.summary = appThemeEntriesStringArray[2]
1094 // Apply the new theme.
1095 AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
1099 // Enable the WebView theme preference if the app theme is not set to light. Google does not allow light themes to display dark WebViews.
1100 webViewThemePreference.isEnabled = (appThemeEntryNumber != 1)
1102 // Get the webView theme entry number that matches the new WebView theme.
1103 val webViewThemeEntryNumber: Int = when (sharedPreferences.getString(getString(R.string.webview_theme_key), getString(R.string.webview_theme_default_value))) {
1104 webViewThemeEntriesStringArray[1] -> 1 // The light theme is selected.
1105 webViewThemeEntryValuesStringArray[2] -> 2 // The dark theme is selected.
1106 else -> 0 // The system default theme is selected.
1109 // Update the WebView theme icon.
1110 if (webViewThemePreference.isEnabled) { // The WebView theme preference is enabled.
1111 when (webViewThemeEntryNumber) {
1112 // The system default WebView theme is selected.
1114 // Get the current theme status.
1115 val currentThemeStatus = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
1117 // Set the icon according to the app theme.
1118 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO)
1119 webViewThemePreference.setIcon(R.drawable.webview_light_theme)
1121 webViewThemePreference.setIcon(R.drawable.webview_dark_theme)
1124 // The light WebView theme is selected.
1127 webViewThemePreference.setIcon(R.drawable.webview_light_theme)
1130 // The dark WebView theme is selected.
1133 webViewThemePreference.setIcon(R.drawable.webview_dark_theme)
1136 } else { // The WebView theme preference is disabled.
1137 webViewThemePreference.setIcon(R.drawable.webview_theme_ghosted)
1141 getString(R.string.webview_theme_key) -> {
1142 // Get the webView theme entry number that matches the new WebView theme.
1143 val newWebViewThemeEntryNumber: Int = when (sharedPreferences.getString(getString(R.string.webview_theme_key), getString(R.string.webview_theme_default_value))) {
1144 webViewThemeEntriesStringArray[1] -> 1 // The light theme is selected.
1145 webViewThemeEntryValuesStringArray[2] -> 2 // The dark theme is selected.
1146 else -> 0 // The system default theme is selected.
1149 // Update the WebView theme icon.
1150 when (newWebViewThemeEntryNumber) {
1151 // The system default WebView theme is selected.
1153 // Get the current theme status.
1154 val currentThemeStatus = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
1157 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO)
1158 webViewThemePreference.setIcon(R.drawable.webview_light_theme)
1160 webViewThemePreference.setIcon(R.drawable.webview_dark_theme)
1163 // The light WebView theme is selected.
1166 webViewThemePreference.setIcon(R.drawable.webview_light_theme)
1169 // The dark WebView theme is selected.
1172 webViewThemePreference.setIcon(R.drawable.webview_dark_theme)
1176 // Set the current theme as the summary text for the preference.
1177 webViewThemePreference.summary = webViewThemeEntriesStringArray[newWebViewThemeEntryNumber]
1180 getString(R.string.wide_viewport_key) -> {
1182 if (sharedPreferences.getBoolean(getString(R.string.wide_viewport_key), true))
1183 wideViewportPreference.setIcon(R.drawable.wide_viewport_enabled)
1185 wideViewportPreference.setIcon(R.drawable.wide_viewport_disabled)
1188 getString(R.string.display_webpage_images_key) -> {
1190 if (sharedPreferences.getBoolean(getString(R.string.display_webpage_images_key), true))
1191 displayWebpageImagesPreference.setIcon(R.drawable.images_enabled)
1193 displayWebpageImagesPreference.setIcon(R.drawable.images_disabled)
1199 private fun restartPrivacyBrowser() {
1200 // Create an intent to restart Privacy Browser.
1201 val restartIntent = requireActivity().parentActivityIntent!!
1203 // `Intent.FLAG_ACTIVITY_CLEAR_TASK` removes all activities from the stack. It requires `Intent.FLAG_ACTIVITY_NEW_TASK`.
1204 restartIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
1206 // Create a handler to restart the activity.
1207 val restartHandler = Handler(Looper.getMainLooper())
1209 // Create a runnable to restart the activity.
1210 val restartRunnable = Runnable {
1211 // Restart the activity.
1212 startActivity(restartIntent)
1214 // Kill this instance of Privacy Browser. Otherwise, the app exhibits sporadic behavior after the restart.
1218 // Restart the activity after 400 milliseconds, so that the app has enough time to save the change to the preference.
1219 restartHandler.postDelayed(restartRunnable, 400)