1 /* SPDX-License-Identifier: GPL-3.0-or-later
2 * SPDX-FileCopyrightText: 2016-2024 Soren Stoutner <soren@stoutner.com>
4 * This file is part of Privacy Browser Android <https://www.stoutner.com/privacy-browser-android/>.
6 * This program is free software: you can redistribute it and/or modify it under
7 * the terms of the GNU General Public License as published by the Free Software
8 * Foundation, either version 3 of the License, or (at your option) any later
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
16 * You should have received a copy of the GNU General Public License along with
17 * this program. If not, see <https://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 sortBookmarksAlphabeticallyPreference: Preference
95 private lateinit var swipeToRefreshPreference: Preference
96 private lateinit var trackingQueriesPreference: Preference
97 private lateinit var translatedUserAgentNamesArray: Array<String>
98 private lateinit var ultraListPreference: Preference
99 private lateinit var ultraPrivacyPreference: Preference
100 private lateinit var userAgentDataArray: Array<String>
101 private lateinit var userAgentPreference: Preference
102 private lateinit var userAgentNamesArray: ArrayAdapter<CharSequence>
103 private lateinit var webViewThemeEntriesStringArray: Array<String>
104 private lateinit var webViewThemeEntryValuesStringArray: Array<String>
105 private lateinit var webViewThemePreference: Preference
106 private lateinit var wideViewportPreference: Preference
108 override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
109 // Check if the fragment has been restarted.
110 if (savedInstanceState != null) {
111 // Set the fragment restored flag.
112 fragmentRestarted = true
114 // Save the scroll Y.
115 scrollY = savedInstanceState.getInt(SCROLL_Y)
118 // Load the preferences from the XML file.
119 setPreferencesFromResource(R.xml.preferences, rootKey)
121 // Get a handle for the shared preferences.
122 val sharedPreferences = preferenceScreen.sharedPreferences!!
124 // Get handles for the preferences.
125 javaScriptPreference = findPreference(getString(R.string.javascript_key))!!
126 cookiesPreference = findPreference(getString(R.string.cookies_key))!!
127 domStoragePreference = findPreference(getString(R.string.dom_storage_key))!!
128 userAgentPreference = findPreference(getString(R.string.user_agent_key))!!
129 customUserAgentPreference = findPreference(getString(R.string.custom_user_agent_key))!!
130 incognitoModePreference = findPreference(getString(R.string.incognito_mode_key))!!
131 allowScreenshotsPreference = findPreference(getString(R.string.allow_screenshots_key))!!
132 easyListPreference = findPreference(getString(R.string.easylist_key))!!
133 easyPrivacyPreference = findPreference(getString(R.string.easyprivacy_key))!!
134 fanboyAnnoyanceListPreference = findPreference(getString(R.string.fanboys_annoyance_list_key))!!
135 fanboySocialBlockingListPreference = findPreference(getString(R.string.fanboys_social_blocking_list_key))!!
136 ultraListPreference = findPreference(getString(R.string.ultralist_key))!!
137 ultraPrivacyPreference = findPreference(getString(R.string.ultraprivacy_key))!!
138 blockAllThirdPartyRequestsPreference = findPreference(getString(R.string.block_all_third_party_requests_key))!!
139 trackingQueriesPreference = findPreference(getString(R.string.tracking_queries_key))!!
140 ampRedirectsPreference = findPreference(getString(R.string.amp_redirects_key))!!
141 searchPreference = findPreference(getString(R.string.search_key))!!
142 searchCustomURLPreference = findPreference(getString(R.string.search_custom_url_key))!!
143 proxyPreference = findPreference(getString(R.string.proxy_key))!!
144 proxyCustomUrlPreference = findPreference(getString(R.string.proxy_custom_url_key))!!
145 fullScreenBrowsingModePreference = findPreference(getString(R.string.full_screen_browsing_mode_key))!!
146 hideAppBarPreference = findPreference(getString(R.string.hide_app_bar_key))!!
147 displayUnderCutoutsPreference = findPreference(getString(R.string.display_under_cutouts_key))!!
148 clearEverythingPreference = findPreference(getString(R.string.clear_everything_key))!!
149 clearCookiesPreference = findPreference(getString(R.string.clear_cookies_key))!!
150 clearDomStoragePreference = findPreference(getString(R.string.clear_dom_storage_key))!!
151 clearLogcatPreference = findPreference(getString(R.string.clear_logcat_key))!!
152 clearCachePreference = findPreference(getString(R.string.clear_cache_key))!!
153 homepagePreference = findPreference(getString(R.string.homepage_key))!!
154 fontSizePreference = findPreference(getString(R.string.font_size_key))!!
155 openIntentsInNewTabPreference = findPreference(getString(R.string.open_intents_in_new_tab_key))!!
156 swipeToRefreshPreference = findPreference(getString(R.string.swipe_to_refresh_key))!!
157 downloadProviderPreference = findPreference(getString(R.string.download_provider_key))!!
158 scrollAppBarPreference = findPreference(getString(R.string.scroll_app_bar_key))!!
159 bottomAppBarPreference = findPreference(getString(R.string.bottom_app_bar_key))!!
160 displayAdditionalAppBarIconsPreference = findPreference(getString(R.string.display_additional_app_bar_icons_key))!!
161 sortBookmarksAlphabeticallyPreference = findPreference(getString(R.string.sort_bookmarks_alphabetically_key))!!
162 appThemePreference = findPreference(getString(R.string.app_theme_key))!!
163 webViewThemePreference = findPreference(getString(R.string.webview_theme_key))!!
164 wideViewportPreference = findPreference(getString(R.string.wide_viewport_key))!!
165 displayWebpageImagesPreference = findPreference(getString(R.string.display_webpage_images_key))!!
167 // Set the preference dependencies.
168 domStoragePreference.dependency = getString(R.string.javascript_key)
169 hideAppBarPreference.dependency = getString(R.string.full_screen_browsing_mode_key)
170 displayUnderCutoutsPreference.dependency = getString(R.string.full_screen_browsing_mode_key)
172 // Get strings from the preferences.
173 val userAgentName = sharedPreferences.getString(getString(R.string.user_agent_key), getString(R.string.user_agent_default_value))
174 val searchString = sharedPreferences.getString(getString(R.string.search_key), getString(R.string.search_default_value))
175 val proxyString = sharedPreferences.getString(getString(R.string.proxy_key), getString(R.string.proxy_default_value))
177 // Get booleans that are used in multiple places from the preferences.
178 val javaScriptEnabled = sharedPreferences.getBoolean(getString(R.string.javascript_key), false)
179 val fanboyAnnoyanceListEnabled = sharedPreferences.getBoolean(getString(R.string.fanboys_annoyance_list_key), true)
180 val fanboySocialBlockingEnabled = sharedPreferences.getBoolean(getString(R.string.fanboys_social_blocking_list_key), true)
181 val fullScreenBrowsingMode = sharedPreferences.getBoolean(getString(R.string.full_screen_browsing_mode_key), false)
182 val clearEverything = sharedPreferences.getBoolean(getString(R.string.clear_everything_key), true)
184 // Only enable Fanboy's social blocking list preference if Fanboy's annoyance list is disabled.
185 fanboySocialBlockingListPreference.isEnabled = !fanboyAnnoyanceListEnabled
188 // Inflate a WebView to get the default user agent.
189 val inflater = requireActivity().layoutInflater
191 // `@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.
192 @SuppressLint("InflateParams") val bareWebViewLayout = inflater.inflate(R.layout.bare_webview, null, false)
194 // Get a handle for the bare WebView.
195 val bareWebView = bareWebViewLayout.findViewById<WebView>(R.id.bare_webview)
197 // Get the default user agent.
198 defaultUserAgent = bareWebView.settings.userAgentString
200 // Get the user agent arrays.
201 userAgentNamesArray = ArrayAdapter.createFromResource(requireContext(), R.array.user_agent_names, R.layout.spinner_item)
202 translatedUserAgentNamesArray = resources.getStringArray(R.array.translated_user_agent_names)
203 userAgentDataArray = resources.getStringArray(R.array.user_agent_data)
205 // Populate the user agent summary.
206 when (val userAgentArrayPosition = userAgentNamesArray.getPosition(userAgentName)) {
207 // The user agent name is not on the canonical list.
208 // 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.
209 UNRECOGNIZED_USER_AGENT -> userAgentPreference.summary = userAgentName
211 // Get the user agent text from the webview (which changes based on the version of Android and WebView installed).
212 SETTINGS_WEBVIEW_DEFAULT_USER_AGENT -> userAgentPreference.summary = "${translatedUserAgentNamesArray[userAgentArrayPosition]}:\n$defaultUserAgent"
214 // Display the custom user agent.
215 SETTINGS_CUSTOM_USER_AGENT -> userAgentPreference.setSummary(R.string.custom_user_agent)
217 // Get the user agent summary from the user agent data array.
218 else -> userAgentPreference.summary = "${translatedUserAgentNamesArray[userAgentArrayPosition]}:\n${userAgentDataArray[userAgentArrayPosition]}"
221 // Set the summary text for the custom user agent preference.
222 customUserAgentPreference.summary = sharedPreferences.getString(getString(R.string.custom_user_agent_key), getString(R.string.custom_user_agent_default_value))
224 // Only enable the custom user agent preference if the user agent is set to custom.
225 customUserAgentPreference.isEnabled = (userAgentPreference.summary == getString(R.string.custom_user_agent))
227 // Set the search URL as the summary text for the search preference when the preference screen is loaded.
228 if (searchString == getString(R.string.custom_url_item)) {
229 // Use R.string.custom_url, which will be translated, instead of the array value, which will not.
230 searchPreference.setSummary(R.string.custom_url)
232 // Set the array value as the summary text.
233 searchPreference.summary = searchString
236 // Set the summary text for the search custom URL (the default is `""`).
237 searchCustomURLPreference.summary = sharedPreferences.getString(getString(R.string.search_custom_url_key), getString(R.string.search_custom_url_default_value))
239 // Only enable the search custom URL preference if the search is set to a custom URL.
240 searchCustomURLPreference.isEnabled = (searchString == getString(R.string.custom_url_item))
242 // Set the summary text for the proxy preference.
243 proxyPreference.summary = when (proxyString) {
244 ProxyHelper.NONE -> getString(R.string.no_proxy_enabled)
245 ProxyHelper.TOR -> getString(R.string.tor_enabled)
246 ProxyHelper.I2P -> getString(R.string.i2p_enabled)
247 ProxyHelper.CUSTOM -> getString(R.string.custom_proxy)
248 else -> getString(R.string.no_proxy_enabled)
251 // Set the summary text for the custom proxy URL.
252 proxyCustomUrlPreference.summary = sharedPreferences.getString(getString(R.string.proxy_custom_url_key), getString(R.string.proxy_custom_url_default_value))
254 // Only enable the custom proxy URL if a custom proxy is selected.
255 proxyCustomUrlPreference.isEnabled = proxyString == ProxyHelper.CUSTOM
257 // Set the status of the clear and exit preferences.
258 clearCookiesPreference.isEnabled = !clearEverything
259 clearDomStoragePreference.isEnabled = !clearEverything
260 clearLogcatPreference.isEnabled = !clearEverything
261 clearCachePreference.isEnabled = !clearEverything
263 // Set the homepage URL as the summary text for the homepage preference.
264 homepagePreference.summary = sharedPreferences.getString(getString(R.string.homepage_key), getString(R.string.homepage_default_value))
266 // Set the font size as the summary text for the preference.
267 fontSizePreference.summary = sharedPreferences.getString(getString(R.string.font_size_key), getString(R.string.font_size_default_value)) + "%"
269 // Get the download provider entry values string array
270 downloadProviderEntryValuesStringArray = resources.getStringArray(R.array.download_provider_entry_values)
272 // Set the summary text for the download provider preference.
273 downloadProviderPreference.summary = when (sharedPreferences.getString(getString(R.string.download_provider_key), getString(R.string.download_provider_default_value))) {
274 downloadProviderEntryValuesStringArray[0] -> getString(R.string.download_with_privacy_browser) // Privacy Browser is selected.
275 downloadProviderEntryValuesStringArray[1] -> getString(R.string.download_with_android_download_manager) // Android download manager is selected.
276 else -> getString(R.string.download_with_external_app) // External app is selected.
279 // Get the app theme string arrays.
280 appThemeEntriesStringArray = resources.getStringArray(R.array.app_theme_entries)
281 appThemeEntryValuesStringArray = resources.getStringArray(R.array.app_theme_entry_values)
283 // Get the app theme entry number that matches the current app theme.
284 val appThemeEntryNumber: Int = when (sharedPreferences.getString(getString(R.string.app_theme_key), getString(R.string.app_theme_default_value))) {
285 appThemeEntryValuesStringArray[1] -> 1 // The light theme is selected.
286 appThemeEntryValuesStringArray[2] -> 2 // The dark theme is selected.
287 else -> 0 // The system default theme is selected.
290 // Set the current theme as the summary text for the preference.
291 appThemePreference.summary = appThemeEntriesStringArray[appThemeEntryNumber]
293 // Enable the WebView theme preference if the app theme is not set to light. Google does not allow light themes to display dark WebViews.
294 webViewThemePreference.isEnabled = (appThemeEntryNumber != 1)
296 // Get the WebView theme string arrays.
297 webViewThemeEntriesStringArray = resources.getStringArray(R.array.webview_theme_entries)
298 webViewThemeEntryValuesStringArray = resources.getStringArray(R.array.webview_theme_entry_values)
300 // Get the WebView theme entry number that matches the current WebView theme.
301 val webViewThemeEntryNumber: Int = when (sharedPreferences.getString(getString(R.string.webview_theme_key), getString(R.string.webview_theme_default_value))) {
302 webViewThemeEntryValuesStringArray[1] -> 1 // The light theme is selected.
303 webViewThemeEntryValuesStringArray[2] -> 2 // The dark theme is selected.
304 else -> 0 // The system default theme is selected.
307 // Set the current theme as the summary text for the preference.
308 webViewThemePreference.summary = webViewThemeEntriesStringArray[webViewThemeEntryNumber]
310 // Set the JavaScript icon.
311 if (javaScriptEnabled)
312 javaScriptPreference.setIcon(R.drawable.javascript_enabled)
314 javaScriptPreference.setIcon(R.drawable.privacy_mode)
316 // Set the cookies icon.
317 if (sharedPreferences.getBoolean(getString(R.string.cookies_key), false))
318 cookiesPreference.setIcon(R.drawable.cookies_enabled)
320 cookiesPreference.setIcon(R.drawable.cookies_disabled)
322 // Set the DOM storage icon.
323 if (javaScriptEnabled) { // JavaScript is enabled.
324 if (sharedPreferences.getBoolean(getString(R.string.dom_storage_key), false)) // DOM storage is enabled.
325 domStoragePreference.setIcon(R.drawable.dom_storage_enabled)
326 else // DOM storage is disabled.
327 domStoragePreference.setIcon(R.drawable.dom_storage_disabled)
328 } else { // JavaScript is disabled. DOM storage should be ghosted.
329 domStoragePreference.setIcon(R.drawable.dom_storage_ghosted)
332 // Set the custom user agent icon.
333 if (customUserAgentPreference.isEnabled)
334 customUserAgentPreference.setIcon(R.drawable.custom_user_agent_enabled)
336 customUserAgentPreference.setIcon(R.drawable.custom_user_agent_ghosted)
338 // Set the incognito mode icon.
339 if (sharedPreferences.getBoolean(getString(R.string.incognito_mode_key), false))
340 incognitoModePreference.setIcon(R.drawable.incognito_mode_enabled)
342 incognitoModePreference.setIcon(R.drawable.incognito_mode_disabled)
344 // Set the allow screenshots icon.
345 if (sharedPreferences.getBoolean(getString(R.string.allow_screenshots_key), false))
346 allowScreenshotsPreference.setIcon(R.drawable.allow_screenshots_enabled)
348 allowScreenshotsPreference.setIcon(R.drawable.allow_screenshots_disabled)
350 // Set the EasyList icon.
351 if (sharedPreferences.getBoolean(getString(R.string.easylist_key), true))
352 easyListPreference.setIcon(R.drawable.block_ads_enabled)
354 easyListPreference.setIcon(R.drawable.block_ads_disabled)
356 // Set the EasyPrivacy icon.
357 if (sharedPreferences.getBoolean(getString(R.string.easyprivacy_key), true))
358 easyPrivacyPreference.setIcon(R.drawable.block_tracking_enabled)
360 easyPrivacyPreference.setIcon(R.drawable.block_tracking_disabled)
362 // Set the Fanboy lists icons.
363 if (fanboyAnnoyanceListEnabled) {
364 // Set the Fanboy annoyance list icon.
365 fanboyAnnoyanceListPreference.setIcon(R.drawable.social_media_enabled)
367 // Set the Fanboy social blocking list icon.
368 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_ghosted)
370 // Set the Fanboy annoyance list icon.
371 fanboyAnnoyanceListPreference.setIcon(R.drawable.social_media_disabled)
373 // Set the Fanboy social blocking list icon.
374 if (fanboySocialBlockingEnabled)
375 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_enabled)
377 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_disabled)
380 // Set the UltraList icon.
381 if (sharedPreferences.getBoolean(getString(R.string.ultralist_key), true))
382 ultraListPreference.setIcon(R.drawable.block_ads_enabled)
384 ultraListPreference.setIcon(R.drawable.block_ads_disabled)
386 // Set the UltraPrivacy icon.
387 if (sharedPreferences.getBoolean(getString(R.string.ultraprivacy_key), true))
388 ultraPrivacyPreference.setIcon(R.drawable.block_tracking_enabled)
390 ultraPrivacyPreference.setIcon(R.drawable.block_tracking_disabled)
392 // Set the block all third-party requests icon.
393 if (sharedPreferences.getBoolean(getString(R.string.block_all_third_party_requests), false))
394 blockAllThirdPartyRequestsPreference.setIcon(R.drawable.block_all_third_party_requests_enabled)
396 blockAllThirdPartyRequestsPreference.setIcon(R.drawable.block_all_third_party_requests_disabled)
398 // Set the Tracking Queries icon.
399 if (sharedPreferences.getBoolean(getString(R.string.tracking_queries_key), true))
400 trackingQueriesPreference.setIcon(R.drawable.modify_url_enabled)
402 trackingQueriesPreference.setIcon(R.drawable.modify_url_disabled)
404 // Set the AMP Redirects icon.
405 if (sharedPreferences.getBoolean(getString(R.string.amp_redirects_key), true))
406 ampRedirectsPreference.setIcon(R.drawable.modify_url_enabled)
408 ampRedirectsPreference.setIcon(R.drawable.modify_url_disabled)
410 // Set the search custom URL icon.
411 if (searchCustomURLPreference.isEnabled)
412 searchCustomURLPreference.setIcon(R.drawable.search_custom_enabled)
414 searchCustomURLPreference.setIcon(R.drawable.search_custom_ghosted)
416 // Set the proxy icons according to the theme and status.
417 if (proxyString == ProxyHelper.NONE) { // Proxying is disabled.
418 // Set the main proxy icon to be disabled.
419 proxyPreference.setIcon(R.drawable.proxy_disabled)
421 // Set the custom proxy URL icon to be ghosted.
422 proxyCustomUrlPreference.setIcon(R.drawable.proxy_ghosted)
423 } else { // Proxying is enabled.
424 // Set the main proxy icon to be enabled.
425 proxyPreference.setIcon(R.drawable.proxy_enabled)
427 // Set the custom proxy URL icon according to its status.
428 if (proxyCustomUrlPreference.isEnabled)
429 proxyCustomUrlPreference.setIcon(R.drawable.proxy_enabled)
431 proxyCustomUrlPreference.setIcon(R.drawable.proxy_ghosted)
434 // Set the full-screen browsing mode icons.
435 if (fullScreenBrowsingMode) { // Full-screen browsing mode is enabled.
436 // Set the full screen browsing mode preference icon.
437 fullScreenBrowsingModePreference.setIcon(R.drawable.full_screen_enabled)
439 // Set the hide app bar icon.
440 if (sharedPreferences.getBoolean(getString(R.string.hide_app_bar_key), true))
441 hideAppBarPreference.setIcon(R.drawable.app_bar_enabled)
443 hideAppBarPreference.setIcon(R.drawable.app_bar_disabled)
444 } else { // Full screen browsing mode is disabled.
446 fullScreenBrowsingModePreference.setIcon(R.drawable.full_screen_disabled)
447 hideAppBarPreference.setIcon(R.drawable.app_bar_ghosted)
450 // Set the display under cutouts icon.
451 if (sharedPreferences.getBoolean(getString(R.string.display_under_cutouts_key), false))
452 displayUnderCutoutsPreference.setIcon(R.drawable.display_under_cutouts_enabled)
454 displayUnderCutoutsPreference.setIcon(R.drawable.display_under_cutouts_disabled)
456 // Set the clear everything icon.
457 if (clearEverything) {
458 clearEverythingPreference.setIcon(R.drawable.clear_everything_enabled)
460 clearEverythingPreference.setIcon(R.drawable.clear_everything_disabled)
463 // Set the clear cookies icon.
464 if (clearEverything || sharedPreferences.getBoolean(getString(R.string.clear_cookies_key), true))
465 clearCookiesPreference.setIcon(R.drawable.clear_cookies_enabled)
467 clearCookiesPreference.setIcon(R.drawable.clear_cookies_disabled)
469 // Set the clear DOM storage icon.
470 if (clearEverything || sharedPreferences.getBoolean(getString(R.string.clear_dom_storage_key), true))
471 clearDomStoragePreference.setIcon(R.drawable.clear_dom_storage_enabled)
473 clearDomStoragePreference.setIcon(R.drawable.clear_dom_storage_disabled)
475 // Set the clear logcat icon.
476 if (clearEverything || sharedPreferences.getBoolean(getString(R.string.clear_logcat_key), true))
477 clearLogcatPreference.setIcon(R.drawable.clear_logcat_enabled)
479 clearLogcatPreference.setIcon(R.drawable.clear_logcat_disabled)
481 // Set the clear cache icon.
482 if (clearEverything || sharedPreferences.getBoolean(getString(R.string.clear_cache_key), true))
483 clearCachePreference.setIcon(R.drawable.clear_cache_enabled)
485 clearCachePreference.setIcon(R.drawable.clear_cache_disabled)
487 // Set the open intents in new tab icon.
488 if (sharedPreferences.getBoolean(getString(R.string.open_intents_in_new_tab_key), true))
489 openIntentsInNewTabPreference.setIcon(R.drawable.tab_enabled)
491 openIntentsInNewTabPreference.setIcon(R.drawable.tab_disabled)
493 // Set the swipe to refresh icon.
494 if (sharedPreferences.getBoolean(getString(R.string.swipe_to_refresh_key), true))
495 swipeToRefreshPreference.setIcon(R.drawable.refresh_enabled)
497 swipeToRefreshPreference.setIcon(R.drawable.refresh_disabled)
499 // Set the scroll app bar icon.
500 if (sharedPreferences.getBoolean(getString(R.string.scroll_app_bar_key), false))
501 scrollAppBarPreference.setIcon(R.drawable.app_bar_enabled)
503 scrollAppBarPreference.setIcon(R.drawable.app_bar_disabled)
505 // Set the bottom app bar icon.
506 if (sharedPreferences.getBoolean(getString(R.string.bottom_app_bar_key), false))
507 bottomAppBarPreference.setIcon(R.drawable.bottom_app_bar_enabled)
509 bottomAppBarPreference.setIcon(R.drawable.bottom_app_bar_disabled)
511 // Set the display additional app bar icons icon.
512 if (sharedPreferences.getBoolean(getString(R.string.display_additional_app_bar_icons_key), false))
513 displayAdditionalAppBarIconsPreference.setIcon(R.drawable.more_enabled)
515 displayAdditionalAppBarIconsPreference.setIcon(R.drawable.more_disabled)
517 // Set the sort bookmarks alphabetically icon.
518 if (sharedPreferences.getBoolean(getString(R.string.sort_bookmarks_alphabetically_key), false))
519 sortBookmarksAlphabeticallyPreference.setIcon(R.drawable.sort_by_alpha_enabled)
521 sortBookmarksAlphabeticallyPreference.setIcon(R.drawable.sort_by_alpha_disabled)
523 // Set the WebView theme icon.
524 if (webViewThemePreference.isEnabled) { // The WebView theme preference is enabled.
525 when (webViewThemeEntryNumber) {
526 // The system default WebView theme is selected.
528 // Get the current theme status.
529 val currentThemeStatus = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
531 // Set the icon according to the app theme.
532 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO)
533 webViewThemePreference.setIcon(R.drawable.webview_light_theme)
535 webViewThemePreference.setIcon(R.drawable.webview_dark_theme)
538 // The light WebView theme is selected.
541 webViewThemePreference.setIcon(R.drawable.webview_light_theme)
544 // The dark WebView theme is selected.
547 webViewThemePreference.setIcon(R.drawable.webview_dark_theme)
550 } else { // The WebView theme preference is disabled.
551 webViewThemePreference.setIcon(R.drawable.webview_theme_ghosted)
554 // Set the wide viewport icon.
555 if (sharedPreferences.getBoolean(getString(R.string.wide_viewport_key), true))
556 wideViewportPreference.setIcon(R.drawable.wide_viewport_enabled)
558 wideViewportPreference.setIcon(R.drawable.wide_viewport_disabled)
560 // Set the display webpage images icon.
561 if (sharedPreferences.getBoolean(getString(R.string.display_webpage_images_key), true))
562 displayWebpageImagesPreference.setIcon(R.drawable.images_enabled)
564 displayWebpageImagesPreference.setIcon(R.drawable.images_disabled)
567 // The listener should be unregistered when the app is paused.
568 override fun onPause() {
569 // Run the default commands.
572 // Get a handle for the shared preferences.
573 val sharedPreferences = preferenceScreen.sharedPreferences!!
575 // Unregister the shared preference listener.
576 sharedPreferences.unregisterOnSharedPreferenceChangeListener(sharedPreferenceChangeListener)
579 // The listener should be re-registered when the app is resumed.
580 override fun onResume() {
581 // Run the default commands.
584 // Get a new shared preference change listener.
585 sharedPreferenceChangeListener = getSharedPreferenceChangeListener()
587 // Get a handle for the shared preferences.
588 val sharedPreferences = preferenceScreen.sharedPreferences!!
590 // Re-register the shared preference listener.
591 sharedPreferences.registerOnSharedPreferenceChangeListener(sharedPreferenceChangeListener)
593 // Restore the scroll position if the fragment has been restarted.
594 if (fragmentRestarted) {
595 // Reset the fragment restarted flag.
596 fragmentRestarted = false
598 // Set the scroll position.
599 listView.post { listView.smoothScrollBy(0, scrollY) }
603 override fun onSaveInstanceState(savedInstanceState: Bundle) {
604 // Run the default commands.
605 super.onSaveInstanceState(savedInstanceState)
607 // Save the scroll position.
608 savedInstanceState.putInt(SCROLL_Y, listView.computeVerticalScrollOffset())
611 private fun getSharedPreferenceChangeListener(): OnSharedPreferenceChangeListener {
612 // Return the shared preference change listener.
613 return OnSharedPreferenceChangeListener { sharedPreferences: SharedPreferences, key: String? ->
615 getString(R.string.javascript_key) -> {
616 // Update the icons and the DOM storage preference status.
617 if (sharedPreferences.getBoolean(getString(R.string.javascript_key), false)) { // The JavaScript preference is enabled.
618 // Update the icon for the JavaScript preference.
619 javaScriptPreference.setIcon(R.drawable.javascript_enabled)
621 // Update the status of the DOM storage preference.
622 domStoragePreference.isEnabled = true
624 // Update the icon for the DOM storage preference.
625 if (sharedPreferences.getBoolean(getString(R.string.dom_storage_key), false))
626 domStoragePreference.setIcon(R.drawable.dom_storage_enabled)
628 domStoragePreference.setIcon(R.drawable.dom_storage_disabled)
629 } else { // The JavaScript preference is disabled.
630 // Update the icon for the JavaScript preference.
631 javaScriptPreference.setIcon(R.drawable.privacy_mode)
633 // Update the status of the DOM storage preference.
634 domStoragePreference.isEnabled = false
636 // Set the icon for DOM storage preference to be ghosted.
637 domStoragePreference.setIcon(R.drawable.dom_storage_ghosted)
641 getString(R.string.cookies_key) -> {
643 if (sharedPreferences.getBoolean(getString(R.string.cookies_key), false))
644 cookiesPreference.setIcon(R.drawable.cookies_enabled)
646 cookiesPreference.setIcon(R.drawable.cookies_disabled)
649 getString(R.string.dom_storage_key) -> {
651 if (sharedPreferences.getBoolean(getString(R.string.dom_storage_key), false))
652 domStoragePreference.setIcon(R.drawable.dom_storage_enabled)
654 domStoragePreference.setIcon(R.drawable.dom_storage_disabled)
657 getString(R.string.user_agent_key) -> {
658 // Get the new user agent name.
659 val newUserAgentName = sharedPreferences.getString(getString(R.string.user_agent_key), getString(R.string.user_agent_default_value))
661 // Get the array position for the new user agent name.
662 val newUserAgentArrayPosition = userAgentNamesArray.getPosition(newUserAgentName)
664 // Get the translated new user agent name.
665 val translatedNewUserAgentName = translatedUserAgentNamesArray[newUserAgentArrayPosition]
667 // Populate the user agent summary.
668 when (newUserAgentArrayPosition) {
669 SETTINGS_WEBVIEW_DEFAULT_USER_AGENT -> {
670 // Get the user agent text from the webview (which changes based on the version of Android and WebView installed).
671 userAgentPreference.summary = "$translatedNewUserAgentName:\n$defaultUserAgent"
673 // Disable the custom user agent preference.
674 customUserAgentPreference.isEnabled = false
676 // Set the custom user agent preference icon.
677 customUserAgentPreference.setIcon(R.drawable.custom_user_agent_ghosted)
680 SETTINGS_CUSTOM_USER_AGENT -> {
681 // Set the summary text.
682 userAgentPreference.setSummary(R.string.custom_user_agent)
684 // Enable the custom user agent preference.
685 customUserAgentPreference.isEnabled = true
687 // Set the custom user agent preference icon.
688 customUserAgentPreference.setIcon(R.drawable.custom_user_agent_enabled)
692 // Get the user agent summary from the user agent data array.
693 userAgentPreference.summary = "$translatedNewUserAgentName:\n${userAgentDataArray[newUserAgentArrayPosition]}"
695 // Disable the custom user agent preference.
696 customUserAgentPreference.isEnabled = false
698 // Set the custom user agent preference icon.
699 customUserAgentPreference.setIcon(R.drawable.custom_user_agent_ghosted)
704 getString(R.string.custom_user_agent_key) -> {
705 // Set the new custom user agent as the summary text for the preference.
706 customUserAgentPreference.summary = sharedPreferences.getString(getString(R.string.custom_user_agent_key), getString(R.string.custom_user_agent_default_value))
709 getString(R.string.incognito_mode_key) -> {
711 if (sharedPreferences.getBoolean(getString(R.string.incognito_mode_key), false))
712 incognitoModePreference.setIcon(R.drawable.incognito_mode_enabled)
714 incognitoModePreference.setIcon(R.drawable.incognito_mode_disabled)
717 getString(R.string.allow_screenshots_key) -> {
719 if (sharedPreferences.getBoolean(getString(R.string.allow_screenshots_key), false))
720 allowScreenshotsPreference.setIcon(R.drawable.allow_screenshots_enabled)
722 allowScreenshotsPreference.setIcon(R.drawable.allow_screenshots_disabled)
724 // Restart Privacy Browser.
725 restartPrivacyBrowser()
728 getString(R.string.easylist_key) -> {
730 if (sharedPreferences.getBoolean(getString(R.string.easylist_key), true))
731 easyListPreference.setIcon(R.drawable.block_ads_enabled)
733 easyListPreference.setIcon(R.drawable.block_ads_disabled)
736 getString(R.string.easyprivacy_key) -> {
738 if (sharedPreferences.getBoolean(getString(R.string.easyprivacy_key), true))
739 easyPrivacyPreference.setIcon(R.drawable.block_tracking_enabled)
741 easyPrivacyPreference.setIcon(R.drawable.block_tracking_disabled)
744 getString(R.string.fanboys_annoyance_list_key) -> {
745 // Get the current Fanboy settings.
746 val currentFanboyAnnoyanceList = sharedPreferences.getBoolean(getString(R.string.fanboys_annoyance_list_key), true)
747 val currentFanboySocialBlockingList = sharedPreferences.getBoolean(getString(R.string.fanboys_social_blocking_list_key), true)
749 // Update the Fanboy icons.
750 if (currentFanboyAnnoyanceList) { // Fanboy's annoyance list is enabled.
751 // Update the Fanboy's annoyance list icon.
752 fanboyAnnoyanceListPreference.setIcon(R.drawable.social_media_enabled)
754 // Update the Fanboy's social blocking list icon.
755 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_ghosted)
756 } else { // Fanboy's annoyance list is disabled.
757 // Update the Fanboy's annoyance list icon.
758 fanboyAnnoyanceListPreference.setIcon(R.drawable.social_media_disabled)
760 // Update the Fanboy's social blocking list icon.
761 if (currentFanboySocialBlockingList)
762 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_enabled)
764 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_disabled)
767 // Only enable Fanboy's social blocking list preference if Fanboy's annoyance list preference is disabled.
768 fanboySocialBlockingListPreference.isEnabled = !currentFanboyAnnoyanceList
771 getString(R.string.fanboys_social_blocking_list_key) -> {
773 if (sharedPreferences.getBoolean(getString(R.string.fanboys_social_blocking_list_key), true))
774 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_enabled)
776 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_disabled)
779 getString(R.string.ultralist_key) -> {
781 if (sharedPreferences.getBoolean(getString(R.string.ultralist_key), true))
782 ultraListPreference.setIcon(R.drawable.block_ads_enabled)
784 ultraListPreference.setIcon(R.drawable.block_ads_disabled)
787 getString(R.string.ultraprivacy_key) -> {
789 if (sharedPreferences.getBoolean(getString(R.string.ultraprivacy_key), true))
790 ultraPrivacyPreference.setIcon(R.drawable.block_tracking_enabled)
792 ultraPrivacyPreference.setIcon(R.drawable.block_tracking_disabled)
795 getString(R.string.block_all_third_party_requests_key) -> {
797 if (sharedPreferences.getBoolean(getString(R.string.block_all_third_party_requests_key), false)) {
798 blockAllThirdPartyRequestsPreference.setIcon(R.drawable.block_all_third_party_requests_enabled)
800 blockAllThirdPartyRequestsPreference.setIcon(R.drawable.block_all_third_party_requests_disabled)
804 getString(R.string.tracking_queries_key) -> {
806 if (sharedPreferences.getBoolean(getString(R.string.tracking_queries_key), true))
807 trackingQueriesPreference.setIcon(R.drawable.modify_url_enabled)
809 trackingQueriesPreference.setIcon(R.drawable.modify_url_disabled)
812 getString(R.string.amp_redirects_key) -> {
814 if (sharedPreferences.getBoolean(getString(R.string.amp_redirects_key), true))
815 ampRedirectsPreference.setIcon(R.drawable.modify_url_enabled)
817 ampRedirectsPreference.setIcon(R.drawable.modify_url_disabled)
820 getString(R.string.search_key) -> {
821 // Store the new search string.
822 val newSearchString = sharedPreferences.getString(getString(R.string.search_key), getString(R.string.search_default_value))
824 // Update the search and search custom URL preferences.
825 if (newSearchString == getString(R.string.custom_url_item)) { // A custom URL is selected.
826 // Set the summary text to `R.string.custom_url`, which is translated.
827 searchPreference.setSummary(R.string.custom_url)
829 // Enable the search custom URL preference.
830 searchCustomURLPreference.isEnabled = true
832 // Set the search custom URL preference icon.
833 searchCustomURLPreference.setIcon(R.drawable.search_custom_enabled)
834 } else { // A custom URL is not selected.
835 // Set the summary text to the new search string.
836 searchPreference.summary = newSearchString
838 // Disable the search custom URL Preference.
839 searchCustomURLPreference.isEnabled = false
841 // Set the search custom URL preference icon.
842 searchCustomURLPreference.setIcon(R.drawable.search_custom_ghosted)
846 getString(R.string.search_custom_url_key) -> {
847 // Set the new search custom URL as the summary text for the preference.
848 searchCustomURLPreference.summary = sharedPreferences.getString(getString(R.string.search_custom_url_key), getString(R.string.search_custom_url_default_value))
851 getString(R.string.proxy_key) -> {
852 // Get the current proxy string.
853 val currentProxyString = sharedPreferences.getString(getString(R.string.proxy_key), getString(R.string.proxy_default_value))
855 // Update the proxy preference summary text.
856 proxyPreference.summary = when (currentProxyString) {
857 ProxyHelper.NONE -> getString(R.string.no_proxy_enabled)
858 ProxyHelper.TOR -> getString(R.string.tor_enabled)
859 ProxyHelper.I2P -> getString(R.string.i2p_enabled)
860 ProxyHelper.CUSTOM -> getString(R.string.custom_proxy)
861 else -> getString(R.string.no_proxy_enabled)
864 // Update the status of the custom URL preference.
865 proxyCustomUrlPreference.isEnabled = currentProxyString == ProxyHelper.CUSTOM
868 if (currentProxyString == ProxyHelper.NONE) { // Proxying is disabled.
869 // Set the main proxy icon to be disabled
870 proxyPreference.setIcon(R.drawable.proxy_disabled)
872 // Set the custom proxy URL icon to be ghosted.
873 proxyCustomUrlPreference.setIcon(R.drawable.proxy_ghosted)
874 } else { // Proxying is enabled.
875 // Set the main proxy icon to be enabled.
876 proxyPreference.setIcon(R.drawable.proxy_enabled)
878 /// Set the custom proxy URL icon according to its status.
879 if (proxyCustomUrlPreference.isEnabled)
880 proxyCustomUrlPreference.setIcon(R.drawable.proxy_enabled)
882 proxyCustomUrlPreference.setIcon(R.drawable.proxy_ghosted)
886 getString(R.string.proxy_custom_url_key) -> {
887 // Set the summary text for the proxy custom URL.
888 proxyCustomUrlPreference.summary = sharedPreferences.getString(getString(R.string.proxy_custom_url_key), getString(R.string.proxy_custom_url_default_value))
891 getString(R.string.full_screen_browsing_mode_key) -> {
893 if (sharedPreferences.getBoolean(getString(R.string.full_screen_browsing_mode_key), false)) { // Full screen browsing is enabled.
894 // Set the full screen browsing mode preference icon.
895 fullScreenBrowsingModePreference.setIcon(R.drawable.full_screen_enabled)
897 // Set the hide app bar preference icon.
898 if (sharedPreferences.getBoolean(getString(R.string.hide_app_bar_key), true))
899 hideAppBarPreference.setIcon(R.drawable.app_bar_enabled)
901 hideAppBarPreference.setIcon(R.drawable.app_bar_disabled)
902 } else { // Full screen browsing is disabled.
904 fullScreenBrowsingModePreference.setIcon(R.drawable.full_screen_disabled)
905 hideAppBarPreference.setIcon(R.drawable.app_bar_ghosted)
909 getString(R.string.hide_app_bar_key) -> {
911 if (sharedPreferences.getBoolean(getString(R.string.hide_app_bar_key), true))
912 hideAppBarPreference.setIcon(R.drawable.app_bar_enabled)
914 hideAppBarPreference.setIcon(R.drawable.app_bar_disabled)
917 getString(R.string.display_under_cutouts_key) -> {
919 if (sharedPreferences.getBoolean(getString(R.string.display_under_cutouts_key), false))
920 displayUnderCutoutsPreference.setIcon(R.drawable.display_under_cutouts_enabled)
922 displayUnderCutoutsPreference.setIcon(R.drawable.display_under_cutouts_disabled)
924 // Restart Privacy Browser if the API < 35.
925 if (Build.VERSION.SDK_INT < 35)
926 restartPrivacyBrowser()
929 getString(R.string.clear_everything_key) -> {
930 // Store the new clear everything status
931 val newClearEverythingBoolean = sharedPreferences.getBoolean(getString(R.string.clear_everything_key), true)
933 // Update the status of the clear and exit preferences.
934 clearCookiesPreference.isEnabled = !newClearEverythingBoolean
935 clearDomStoragePreference.isEnabled = !newClearEverythingBoolean
936 clearLogcatPreference.isEnabled = !newClearEverythingBoolean
937 clearCachePreference.isEnabled = !newClearEverythingBoolean
939 // Update the clear everything preference icon.
940 if (newClearEverythingBoolean)
941 clearEverythingPreference.setIcon(R.drawable.clear_everything_enabled)
943 clearEverythingPreference.setIcon(R.drawable.clear_everything_disabled)
945 // Update the clear cookies preference icon.
946 if (newClearEverythingBoolean || sharedPreferences.getBoolean(getString(R.string.clear_cookies_key), true))
947 clearCookiesPreference.setIcon(R.drawable.clear_cookies_enabled)
949 clearCookiesPreference.setIcon(R.drawable.clear_cookies_disabled)
951 // Update the clear dom storage preference icon.
952 if (newClearEverythingBoolean || sharedPreferences.getBoolean(getString(R.string.clear_dom_storage_key), true))
953 clearDomStoragePreference.setIcon(R.drawable.clear_dom_storage_enabled)
955 clearDomStoragePreference.setIcon(R.drawable.clear_dom_storage_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_logcat_key) -> {
988 if (sharedPreferences.getBoolean(getString(R.string.clear_logcat_key), true))
989 clearLogcatPreference.setIcon(R.drawable.clear_logcat_enabled)
991 clearLogcatPreference.setIcon(R.drawable.clear_logcat_disabled)
994 getString(R.string.clear_cache_key) -> {
996 if (sharedPreferences.getBoolean(getString(R.string.clear_cache_key), true))
997 clearCachePreference.setIcon(R.drawable.clear_cache_enabled)
999 clearCachePreference.setIcon(R.drawable.clear_cache_disabled)
1002 getString(R.string.homepage_key) -> {
1003 // Set the new homepage URL as the summary text for the Homepage preference.
1004 homepagePreference.summary = sharedPreferences.getString(getString(R.string.homepage_key), getString(R.string.homepage_default_value))
1007 getString(R.string.font_size_key) -> {
1008 // Update the font size summary text.
1009 fontSizePreference.summary = sharedPreferences.getString(getString(R.string.font_size_key), getString(R.string.font_size_default_value)) + "%"
1012 getString(R.string.open_intents_in_new_tab_key) -> {
1014 if (sharedPreferences.getBoolean(getString(R.string.open_intents_in_new_tab_key), true))
1015 openIntentsInNewTabPreference.setIcon(R.drawable.tab_enabled)
1017 openIntentsInNewTabPreference.setIcon(R.drawable.tab_disabled)
1020 getString(R.string.swipe_to_refresh_key) -> {
1022 if (sharedPreferences.getBoolean(getString(R.string.swipe_to_refresh_key), true))
1023 swipeToRefreshPreference.setIcon(R.drawable.refresh_enabled)
1025 swipeToRefreshPreference.setIcon(R.drawable.refresh_disabled)
1028 getString(R.string.download_provider_key) -> {
1029 // Set the summary text for the download provider preference.
1030 downloadProviderPreference.summary = when (sharedPreferences.getString(getString(R.string.download_provider_key), getString(R.string.download_provider_default_value))) {
1031 downloadProviderEntryValuesStringArray[0] -> getString(R.string.download_with_privacy_browser) // Privacy Browser is selected.
1032 downloadProviderEntryValuesStringArray[1] -> getString(R.string.download_with_android_download_manager) // Android download manager is selected.
1033 else -> getString(R.string.download_with_external_app) // External app is selected.
1037 getString(R.string.scroll_app_bar_key) -> {
1039 if (sharedPreferences.getBoolean(getString(R.string.scroll_app_bar_key), false))
1040 scrollAppBarPreference.setIcon(R.drawable.app_bar_enabled)
1042 scrollAppBarPreference.setIcon(R.drawable.app_bar_disabled)
1045 getString(R.string.bottom_app_bar_key) -> {
1047 if (sharedPreferences.getBoolean(getString(R.string.bottom_app_bar_key), false))
1048 bottomAppBarPreference.setIcon(R.drawable.bottom_app_bar_enabled)
1050 bottomAppBarPreference.setIcon(R.drawable.bottom_app_bar_disabled)
1052 // Restart Privacy Browser.
1053 restartPrivacyBrowser()
1056 getString(R.string.display_additional_app_bar_icons_key) -> {
1058 if (sharedPreferences.getBoolean(getString(R.string.display_additional_app_bar_icons_key), false))
1059 displayAdditionalAppBarIconsPreference.setIcon(R.drawable.more_enabled)
1061 displayAdditionalAppBarIconsPreference.setIcon(R.drawable.more_disabled)
1063 // Restart Privacy Browser.
1064 restartPrivacyBrowser()
1067 getString(R.string.sort_bookmarks_alphabetically_key) -> {
1069 if (sharedPreferences.getBoolean(getString(R.string.sort_bookmarks_alphabetically_key), false))
1070 sortBookmarksAlphabeticallyPreference.setIcon(R.drawable.sort_by_alpha_enabled)
1072 sortBookmarksAlphabeticallyPreference.setIcon(R.drawable.sort_by_alpha_disabled)
1075 getString(R.string.app_theme_key) -> {
1076 // Get the app theme entry number that matches the current app theme.
1077 val appThemeEntryNumber: Int = when (sharedPreferences.getString(getString(R.string.app_theme_key), getString(R.string.app_theme_default_value))) {
1078 appThemeEntryValuesStringArray[1] -> 1 // The light theme is selected.
1079 appThemeEntryValuesStringArray[2] -> 2 // The dark theme is selected.
1080 else -> 0 // The system default theme is selected.
1083 // Update the system according to the new theme.
1084 when (appThemeEntryNumber) {
1085 0 -> { // The system default theme is selected.
1086 // Update the theme preference summary text.
1087 appThemePreference.summary = appThemeEntriesStringArray[0]
1089 // Apply the new theme.
1090 if (Build.VERSION.SDK_INT >= 28) { // The system default theme is supported.
1091 // Follow the system default theme.
1092 AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
1093 } else { // The system default theme is not supported.
1094 // Follow the battery saver mode.
1095 AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_AUTO_BATTERY)
1099 1 -> { // The light theme is selected.
1100 // Update the theme preference summary text.
1101 appThemePreference.summary = appThemeEntriesStringArray[1]
1103 // Apply the new theme.
1104 AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
1107 2 -> { // The dark theme is selected.
1108 // Update the theme preference summary text.
1109 appThemePreference.summary = appThemeEntriesStringArray[2]
1111 // Apply the new theme.
1112 AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
1116 // Enable the WebView theme preference if the app theme is not set to light. Google does not allow light themes to display dark WebViews.
1117 webViewThemePreference.isEnabled = (appThemeEntryNumber != 1)
1119 // Get the webView theme entry number that matches the new WebView theme.
1120 val webViewThemeEntryNumber: Int = when (sharedPreferences.getString(getString(R.string.webview_theme_key), getString(R.string.webview_theme_default_value))) {
1121 webViewThemeEntriesStringArray[1] -> 1 // The light theme is selected.
1122 webViewThemeEntryValuesStringArray[2] -> 2 // The dark theme is selected.
1123 else -> 0 // The system default theme is selected.
1126 // Update the WebView theme icon.
1127 if (webViewThemePreference.isEnabled) { // The WebView theme preference is enabled.
1128 when (webViewThemeEntryNumber) {
1129 // The system default WebView theme is selected.
1131 // Get the current theme status.
1132 val currentThemeStatus = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
1134 // Set the icon according to the app theme.
1135 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO)
1136 webViewThemePreference.setIcon(R.drawable.webview_light_theme)
1138 webViewThemePreference.setIcon(R.drawable.webview_dark_theme)
1141 // The light WebView theme is selected.
1144 webViewThemePreference.setIcon(R.drawable.webview_light_theme)
1147 // The dark WebView theme is selected.
1150 webViewThemePreference.setIcon(R.drawable.webview_dark_theme)
1153 } else { // The WebView theme preference is disabled.
1154 webViewThemePreference.setIcon(R.drawable.webview_theme_ghosted)
1158 getString(R.string.webview_theme_key) -> {
1159 // Get the webView theme entry number that matches the new WebView theme.
1160 val newWebViewThemeEntryNumber: Int = when (sharedPreferences.getString(getString(R.string.webview_theme_key), getString(R.string.webview_theme_default_value))) {
1161 webViewThemeEntriesStringArray[1] -> 1 // The light theme is selected.
1162 webViewThemeEntryValuesStringArray[2] -> 2 // The dark theme is selected.
1163 else -> 0 // The system default theme is selected.
1166 // Update the WebView theme icon.
1167 when (newWebViewThemeEntryNumber) {
1168 // The system default WebView theme is selected.
1170 // Get the current theme status.
1171 val currentThemeStatus = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
1174 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO)
1175 webViewThemePreference.setIcon(R.drawable.webview_light_theme)
1177 webViewThemePreference.setIcon(R.drawable.webview_dark_theme)
1180 // The light WebView theme is selected.
1183 webViewThemePreference.setIcon(R.drawable.webview_light_theme)
1186 // The dark WebView theme is selected.
1189 webViewThemePreference.setIcon(R.drawable.webview_dark_theme)
1193 // Set the current theme as the summary text for the preference.
1194 webViewThemePreference.summary = webViewThemeEntriesStringArray[newWebViewThemeEntryNumber]
1197 getString(R.string.wide_viewport_key) -> {
1199 if (sharedPreferences.getBoolean(getString(R.string.wide_viewport_key), true))
1200 wideViewportPreference.setIcon(R.drawable.wide_viewport_enabled)
1202 wideViewportPreference.setIcon(R.drawable.wide_viewport_disabled)
1205 getString(R.string.display_webpage_images_key) -> {
1207 if (sharedPreferences.getBoolean(getString(R.string.display_webpage_images_key), true))
1208 displayWebpageImagesPreference.setIcon(R.drawable.images_enabled)
1210 displayWebpageImagesPreference.setIcon(R.drawable.images_disabled)
1216 private fun restartPrivacyBrowser() {
1217 // Create an intent to restart Privacy Browser.
1218 val restartIntent = requireActivity().parentActivityIntent!!
1220 // `Intent.FLAG_ACTIVITY_CLEAR_TASK` removes all activities from the stack. It requires `Intent.FLAG_ACTIVITY_NEW_TASK`.
1221 restartIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
1223 // Create a handler to restart the activity.
1224 val restartHandler = Handler(Looper.getMainLooper())
1226 // Create a runnable to restart the activity.
1227 val restartRunnable = Runnable {
1228 // Restart the activity.
1229 startActivity(restartIntent)
1231 // Kill this instance of Privacy Browser. Otherwise, the app exhibits sporadic behavior after the restart.
1235 // Restart the activity after 400 milliseconds, so that the app has enough time to save the change to the preference.
1236 restartHandler.postDelayed(restartRunnable, 400)