2 * Copyright 2016-2023 Soren Stoutner <soren@stoutner.com>.
4 * This file is part of Privacy Browser Android <https://www.stoutner.com/privacy-browser-android>.
6 * Privacy Browser Android is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * Privacy Browser Android is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with Privacy Browser Android. If not, see <http://www.gnu.org/licenses/>.
20 package com.stoutner.privacybrowser.fragments
22 import android.annotation.SuppressLint
23 import android.content.Intent
24 import android.content.SharedPreferences
25 import android.content.SharedPreferences.OnSharedPreferenceChangeListener
26 import android.content.res.Configuration
27 import android.os.Build
28 import android.os.Bundle
29 import android.os.Handler
30 import android.os.Looper
31 import android.webkit.WebView
32 import android.widget.ArrayAdapter
34 import androidx.appcompat.app.AppCompatDelegate
35 import androidx.preference.Preference
36 import androidx.preference.PreferenceCategory
37 import androidx.preference.PreferenceFragmentCompat
39 import com.stoutner.privacybrowser.R
40 import com.stoutner.privacybrowser.activities.SETTINGS_CUSTOM_USER_AGENT
41 import com.stoutner.privacybrowser.activities.SETTINGS_WEBVIEW_DEFAULT_USER_AGENT
42 import com.stoutner.privacybrowser.activities.UNRECOGNIZED_USER_AGENT
43 import com.stoutner.privacybrowser.helpers.ProxyHelper
44 import kotlin.system.exitProcess
46 // Define the class constants.
47 private const val SCROLL_Y = "scroll_y"
49 class SettingsFragment : PreferenceFragmentCompat() {
51 // 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.
52 private var fragmentRestarted: Boolean = false
53 private var scrollY: Int = 0
56 // Declare the class variables.
57 private lateinit var allowScreenshotsPreference: Preference
58 private lateinit var ampRedirectsPreference: Preference
59 private lateinit var appThemeEntriesStringArray: Array<String>
60 private lateinit var appThemeEntryValuesStringArray: Array<String>
61 private lateinit var appThemePreference: Preference
62 private lateinit var blockAllThirdPartyRequestsPreference: Preference
63 private lateinit var bottomAppBarPreference: Preference
64 private lateinit var clearCachePreference: Preference
65 private lateinit var clearCookiesPreference: Preference
66 private lateinit var clearDomStoragePreference: Preference
67 private lateinit var clearEverythingPreference: Preference
68 private lateinit var clearFormDataPreference: Preference // The clear form data preference can be removed once the minimum API >= 26.
69 private lateinit var clearLogcatPreference: Preference
70 private lateinit var cookiesPreference: Preference
71 private lateinit var customUserAgentPreference: Preference
72 private lateinit var defaultUserAgent: String
73 private lateinit var displayAdditionalAppBarIconsPreference: Preference
74 private lateinit var displayWebpageImagesPreference: Preference
75 private lateinit var domStoragePreference: Preference
76 private lateinit var downloadWithExternalAppPreference: Preference
77 private lateinit var easyListPreference: Preference
78 private lateinit var easyPrivacyPreference: Preference
79 private lateinit var fanboyAnnoyanceListPreference: Preference
80 private lateinit var fanboySocialBlockingListPreference: Preference
81 private lateinit var fontSizePreference: Preference
82 private lateinit var formDataPreference: Preference // The form data preference can be removed once the minimum API >= 26.
83 private lateinit var fullScreenBrowsingModePreference: Preference
84 private lateinit var hideAppBarPreference: Preference
85 private lateinit var homepagePreference: Preference
86 private lateinit var incognitoModePreference: Preference
87 private lateinit var javaScriptPreference: Preference
88 private lateinit var openIntentsInNewTabPreference: Preference
89 private lateinit var proxyCustomUrlPreference: Preference
90 private lateinit var proxyPreference: Preference
91 private lateinit var scrollAppBarPreference: Preference
92 private lateinit var searchCustomURLPreference: Preference
93 private lateinit var searchPreference: Preference
94 private lateinit var sharedPreferenceChangeListener: OnSharedPreferenceChangeListener
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 formDataPreference = findPreference(getString(R.string.save_form_data_key))!! // The form data preference can be removed once the minimum API >= 26.
129 userAgentPreference = findPreference(getString(R.string.user_agent_key))!!
130 customUserAgentPreference = findPreference(getString(R.string.custom_user_agent_key))!!
131 incognitoModePreference = findPreference(getString(R.string.incognito_mode_key))!!
132 allowScreenshotsPreference = findPreference(getString(R.string.allow_screenshots_key))!!
133 easyListPreference = findPreference(getString(R.string.easylist_key))!!
134 easyPrivacyPreference = findPreference(getString(R.string.easyprivacy_key))!!
135 fanboyAnnoyanceListPreference = findPreference(getString(R.string.fanboys_annoyance_list_key))!!
136 fanboySocialBlockingListPreference = findPreference(getString(R.string.fanboys_social_blocking_list_key))!!
137 ultraListPreference = findPreference(getString(R.string.ultralist_key))!!
138 ultraPrivacyPreference = findPreference(getString(R.string.ultraprivacy_key))!!
139 blockAllThirdPartyRequestsPreference = findPreference(getString(R.string.block_all_third_party_requests_key))!!
140 trackingQueriesPreference = findPreference(getString(R.string.tracking_queries_key))!!
141 ampRedirectsPreference = findPreference(getString(R.string.amp_redirects_key))!!
142 searchPreference = findPreference(getString(R.string.search_key))!!
143 searchCustomURLPreference = findPreference(getString(R.string.search_custom_url_key))!!
144 proxyPreference = findPreference(getString(R.string.proxy_key))!!
145 proxyCustomUrlPreference = findPreference(getString(R.string.proxy_custom_url_key))!!
146 fullScreenBrowsingModePreference = findPreference(getString(R.string.full_screen_browsing_mode_key))!!
147 hideAppBarPreference = findPreference(getString(R.string.hide_app_bar_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 clearFormDataPreference = findPreference(getString(R.string.clear_form_data_key))!! // The clear form data preference can be removed once the minimum API >= 26.
152 clearLogcatPreference = findPreference(getString(R.string.clear_logcat_key))!!
153 clearCachePreference = findPreference(getString(R.string.clear_cache_key))!!
154 homepagePreference = findPreference(getString(R.string.homepage_key))!!
155 fontSizePreference = findPreference(getString(R.string.font_size_key))!!
156 openIntentsInNewTabPreference = findPreference(getString(R.string.open_intents_in_new_tab_key))!!
157 swipeToRefreshPreference = findPreference(getString(R.string.swipe_to_refresh_key))!!
158 downloadWithExternalAppPreference = findPreference(getString(R.string.download_with_external_app_key))!!
159 scrollAppBarPreference = findPreference(getString(R.string.scroll_app_bar_key))!!
160 bottomAppBarPreference = findPreference(getString(R.string.bottom_app_bar_key))!!
161 displayAdditionalAppBarIconsPreference = findPreference(getString(R.string.display_additional_app_bar_icons_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)
171 // Get strings from the preferences.
172 val userAgentName = sharedPreferences.getString(getString(R.string.user_agent_key), getString(R.string.user_agent_default_value))
173 val searchString = sharedPreferences.getString(getString(R.string.search_key), getString(R.string.search_default_value))
174 val proxyString = sharedPreferences.getString(getString(R.string.proxy_key), getString(R.string.proxy_default_value))
176 // Get booleans that are used in multiple places from the preferences.
177 val javaScriptEnabled = sharedPreferences.getBoolean(getString(R.string.javascript_key), false)
178 val fanboyAnnoyanceListEnabled = sharedPreferences.getBoolean(getString(R.string.fanboys_annoyance_list_key), true)
179 val fanboySocialBlockingEnabled = sharedPreferences.getBoolean(getString(R.string.fanboys_social_blocking_list_key), true)
180 val fullScreenBrowsingMode = sharedPreferences.getBoolean(getString(R.string.full_screen_browsing_mode_key), false)
181 val clearEverything = sharedPreferences.getBoolean(getString(R.string.clear_everything_key), true)
183 // Remove the form data preferences if the API is >= 26 as they no longer do anything.
184 if (Build.VERSION.SDK_INT >= 26) {
185 // Get handles for the categories.
186 val privacyCategory = findPreference<PreferenceCategory>(getString(R.string.privacy_category_key))!!
187 val clearAndExitCategory = findPreference<PreferenceCategory>(getString(R.string.clear_and_exit_category_key))!!
189 // Remove the form data preferences.
190 privacyCategory.removePreference(formDataPreference)
191 clearAndExitCategory.removePreference(clearFormDataPreference)
194 // Remove the WebView theme preference if the API < 29.
195 if (Build.VERSION.SDK_INT < 29) {
196 // Get a handle for the general category.
197 val generalCategory = findPreference<PreferenceCategory>(getString(R.string.general_category_key))!!
199 // Remove the WebView theme preference.
200 generalCategory.removePreference(webViewThemePreference)
203 // Only enable Fanboy's social blocking list preference if Fanboy's annoyance list is disabled.
204 fanboySocialBlockingListPreference.isEnabled = !fanboyAnnoyanceListEnabled
207 // Inflate a WebView to get the default user agent.
208 val inflater = requireActivity().layoutInflater
210 // `@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.
211 @SuppressLint("InflateParams") val bareWebViewLayout = inflater.inflate(R.layout.bare_webview, null, false)
213 // Get a handle for the bare WebView.
214 val bareWebView = bareWebViewLayout.findViewById<WebView>(R.id.bare_webview)
216 // Get the default user agent.
217 defaultUserAgent = bareWebView.settings.userAgentString
219 // Get the user agent arrays.
220 userAgentNamesArray = ArrayAdapter.createFromResource(requireContext(), R.array.user_agent_names, R.layout.spinner_item)
221 translatedUserAgentNamesArray = resources.getStringArray(R.array.translated_user_agent_names)
222 userAgentDataArray = resources.getStringArray(R.array.user_agent_data)
224 // Populate the user agent summary.
225 when (val userAgentArrayPosition = userAgentNamesArray.getPosition(userAgentName)) {
226 // The user agent name is not on the canonical list.
227 // 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.
228 UNRECOGNIZED_USER_AGENT -> userAgentPreference.summary = userAgentName
230 // Get the user agent text from the webview (which changes based on the version of Android and WebView installed).
231 SETTINGS_WEBVIEW_DEFAULT_USER_AGENT -> userAgentPreference.summary = "${translatedUserAgentNamesArray[userAgentArrayPosition]}:\n$defaultUserAgent"
233 // Display the custom user agent.
234 SETTINGS_CUSTOM_USER_AGENT -> userAgentPreference.setSummary(R.string.custom_user_agent)
236 // Get the user agent summary from the user agent data array.
237 else -> userAgentPreference.summary = "${translatedUserAgentNamesArray[userAgentArrayPosition]}:\n${userAgentDataArray[userAgentArrayPosition]}"
240 // Set the summary text for the custom user agent preference.
241 customUserAgentPreference.summary = sharedPreferences.getString(getString(R.string.custom_user_agent_key), getString(R.string.custom_user_agent_default_value))
243 // Only enable the custom user agent preference if the user agent is set to custom.
244 customUserAgentPreference.isEnabled = (userAgentPreference.summary == getString(R.string.custom_user_agent))
246 // Set the search URL as the summary text for the search preference when the preference screen is loaded.
247 if (searchString == getString(R.string.custom_url_item)) {
248 // Use R.string.custom_url, which will be translated, instead of the array value, which will not.
249 searchPreference.setSummary(R.string.custom_url)
251 // Set the array value as the summary text.
252 searchPreference.summary = searchString
255 // Set the summary text for the search custom URL (the default is `""`).
256 searchCustomURLPreference.summary = sharedPreferences.getString(getString(R.string.search_custom_url_key), getString(R.string.search_custom_url_default_value))
258 // Only enable the search custom URL preference if the search is set to a custom URL.
259 searchCustomURLPreference.isEnabled = (searchString == getString(R.string.custom_url_item))
261 // Set the summary text for the proxy preference.
262 proxyPreference.summary = when (proxyString) {
263 ProxyHelper.NONE -> getString(R.string.no_proxy_enabled)
264 ProxyHelper.TOR -> getString(R.string.tor_enabled)
265 ProxyHelper.I2P -> getString(R.string.i2p_enabled)
266 ProxyHelper.CUSTOM -> getString(R.string.custom_proxy)
267 else -> getString(R.string.no_proxy_enabled)
270 // Set the summary text for the custom proxy URL.
271 proxyCustomUrlPreference.summary = sharedPreferences.getString(getString(R.string.proxy_custom_url_key), getString(R.string.proxy_custom_url_default_value))
273 // Only enable the custom proxy URL if a custom proxy is selected.
274 proxyCustomUrlPreference.isEnabled = proxyString == ProxyHelper.CUSTOM
276 // Set the status of the clear and exit preferences.
277 clearCookiesPreference.isEnabled = !clearEverything
278 clearDomStoragePreference.isEnabled = !clearEverything
279 clearFormDataPreference.isEnabled = !clearEverything // Clear form data can be removed once the minimum API is >= 26.
280 clearLogcatPreference.isEnabled = !clearEverything
281 clearCachePreference.isEnabled = !clearEverything
283 // Set the homepage URL as the summary text for the homepage preference.
284 homepagePreference.summary = sharedPreferences.getString(getString(R.string.homepage_key), getString(R.string.homepage_default_value))
286 // Set the font size as the summary text for the preference.
287 fontSizePreference.summary = sharedPreferences.getString(getString(R.string.font_size_key), getString(R.string.font_size_default_value)) + "%"
289 // Get the app theme string arrays.
290 appThemeEntriesStringArray = resources.getStringArray(R.array.app_theme_entries)
291 appThemeEntryValuesStringArray = resources.getStringArray(R.array.app_theme_entry_values)
293 // Get the app theme entry number that matches the current app theme.
294 val appThemeEntryNumber: Int = when (sharedPreferences.getString(getString(R.string.app_theme_key), getString(R.string.app_theme_default_value))) {
295 appThemeEntryValuesStringArray[1] -> 1 // The light theme is selected.
296 appThemeEntryValuesStringArray[2] -> 2 // The dark theme is selected.
297 else -> 0 // The system default theme is selected.
300 // Set the current theme as the summary text for the preference.
301 appThemePreference.summary = appThemeEntriesStringArray[appThemeEntryNumber]
303 // Enable the WebView theme preference if the app theme is not set to light. Google does not allow light themes to display dark WebViews.
304 webViewThemePreference.isEnabled = (appThemeEntryNumber != 1)
306 // Get the WebView theme string arrays.
307 webViewThemeEntriesStringArray = resources.getStringArray(R.array.webview_theme_entries)
308 webViewThemeEntryValuesStringArray = resources.getStringArray(R.array.webview_theme_entry_values)
310 // Get the WebView theme entry number that matches the current WebView theme.
311 val webViewThemeEntryNumber: Int = when (sharedPreferences.getString(getString(R.string.webview_theme_key), getString(R.string.webview_theme_default_value))) {
312 webViewThemeEntryValuesStringArray[1] -> 1 // The light theme is selected.
313 webViewThemeEntryValuesStringArray[2] -> 2 // The dark theme is selected.
314 else -> 0 // The system default theme is selected.
317 // Set the current theme as the summary text for the preference.
318 webViewThemePreference.summary = webViewThemeEntriesStringArray[webViewThemeEntryNumber]
320 // Set the JavaScript icon.
321 if (javaScriptEnabled)
322 javaScriptPreference.setIcon(R.drawable.javascript_enabled)
324 javaScriptPreference.setIcon(R.drawable.privacy_mode)
326 // Set the cookies icon.
327 if (sharedPreferences.getBoolean(getString(R.string.cookies_key), false))
328 cookiesPreference.setIcon(R.drawable.cookies_enabled)
330 cookiesPreference.setIcon(R.drawable.cookies_disabled)
332 // Set the DOM storage icon.
333 if (javaScriptEnabled) { // JavaScript is enabled.
334 if (sharedPreferences.getBoolean(getString(R.string.dom_storage_key), false)) // DOM storage is enabled.
335 domStoragePreference.setIcon(R.drawable.dom_storage_enabled)
336 else // DOM storage is disabled.
337 domStoragePreference.setIcon(R.drawable.dom_storage_disabled)
338 } else { // JavaScript is disabled. DOM storage should be ghosted.
339 domStoragePreference.setIcon(R.drawable.dom_storage_ghosted)
342 // Set the save form data icon if API < 26. Save form data has no effect on API >= 26.
343 if (Build.VERSION.SDK_INT < 26) {
344 if (sharedPreferences.getBoolean(getString(R.string.save_form_data_key), false))
345 formDataPreference.setIcon(R.drawable.form_data_enabled)
347 formDataPreference.setIcon(R.drawable.form_data_disabled)
350 // Set the custom user agent icon.
351 if (customUserAgentPreference.isEnabled)
352 customUserAgentPreference.setIcon(R.drawable.custom_user_agent_enabled)
354 customUserAgentPreference.setIcon(R.drawable.custom_user_agent_ghosted)
356 // Set the incognito mode icon.
357 if (sharedPreferences.getBoolean(getString(R.string.incognito_mode_key), false))
358 incognitoModePreference.setIcon(R.drawable.incognito_mode_enabled)
360 incognitoModePreference.setIcon(R.drawable.incognito_mode_disabled)
362 // Set the allow screenshots icon.
363 if (sharedPreferences.getBoolean(getString(R.string.allow_screenshots_key), false))
364 allowScreenshotsPreference.setIcon(R.drawable.allow_screenshots_enabled)
366 allowScreenshotsPreference.setIcon(R.drawable.allow_screenshots_disabled)
368 // Set the EasyList icon.
369 if (sharedPreferences.getBoolean(getString(R.string.easylist_key), true))
370 easyListPreference.setIcon(R.drawable.block_ads_enabled)
372 easyListPreference.setIcon(R.drawable.block_ads_disabled)
374 // Set the EasyPrivacy icon.
375 if (sharedPreferences.getBoolean(getString(R.string.easyprivacy_key), true))
376 easyPrivacyPreference.setIcon(R.drawable.block_tracking_enabled)
378 easyPrivacyPreference.setIcon(R.drawable.block_tracking_disabled)
380 // Set the Fanboy lists icons.
381 if (fanboyAnnoyanceListEnabled) {
382 // Set the Fanboy annoyance list icon.
383 fanboyAnnoyanceListPreference.setIcon(R.drawable.social_media_enabled)
385 // Set the Fanboy social blocking list icon.
386 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_ghosted)
388 // Set the Fanboy annoyance list icon.
389 fanboyAnnoyanceListPreference.setIcon(R.drawable.social_media_disabled)
391 // Set the Fanboy social blocking list icon.
392 if (fanboySocialBlockingEnabled)
393 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_enabled)
395 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_disabled)
398 // Set the UltraList icon.
399 if (sharedPreferences.getBoolean(getString(R.string.ultralist_key), true))
400 ultraListPreference.setIcon(R.drawable.block_ads_enabled)
402 ultraListPreference.setIcon(R.drawable.block_ads_disabled)
404 // Set the UltraPrivacy icon.
405 if (sharedPreferences.getBoolean(getString(R.string.ultraprivacy_key), true))
406 ultraPrivacyPreference.setIcon(R.drawable.block_tracking_enabled)
408 ultraPrivacyPreference.setIcon(R.drawable.block_tracking_disabled)
410 // Set the block all third-party requests icon.
411 if (sharedPreferences.getBoolean(getString(R.string.block_all_third_party_requests), false))
412 blockAllThirdPartyRequestsPreference.setIcon(R.drawable.block_all_third_party_requests_enabled)
414 blockAllThirdPartyRequestsPreference.setIcon(R.drawable.block_all_third_party_requests_disabled)
416 // Set the Tracking Queries icon.
417 if (sharedPreferences.getBoolean(getString(R.string.tracking_queries_key), true))
418 trackingQueriesPreference.setIcon(R.drawable.modify_url_enabled)
420 trackingQueriesPreference.setIcon(R.drawable.modify_url_disabled)
422 // Set the AMP Redirects icon.
423 if (sharedPreferences.getBoolean(getString(R.string.amp_redirects_key), true))
424 ampRedirectsPreference.setIcon(R.drawable.modify_url_enabled)
426 ampRedirectsPreference.setIcon(R.drawable.modify_url_disabled)
428 // Set the search custom URL icon.
429 if (searchCustomURLPreference.isEnabled)
430 searchCustomURLPreference.setIcon(R.drawable.search_custom_enabled)
432 searchCustomURLPreference.setIcon(R.drawable.search_custom_ghosted)
434 // Set the proxy icons according to the theme and status.
435 if (proxyString == ProxyHelper.NONE) { // Proxying is disabled.
436 // Set the main proxy icon to be disabled.
437 proxyPreference.setIcon(R.drawable.proxy_disabled)
439 // Set the custom proxy URL icon to be ghosted.
440 proxyCustomUrlPreference.setIcon(R.drawable.proxy_ghosted)
441 } else { // Proxying is enabled.
442 // Set the main proxy icon to be enabled.
443 proxyPreference.setIcon(R.drawable.proxy_enabled)
445 // Set the custom proxy URL icon according to its status.
446 if (proxyCustomUrlPreference.isEnabled)
447 proxyCustomUrlPreference.setIcon(R.drawable.proxy_enabled)
449 proxyCustomUrlPreference.setIcon(R.drawable.proxy_ghosted)
452 // Set the full-screen browsing mode icons.
453 if (fullScreenBrowsingMode) { // Full-screen browsing mode is enabled.
454 // Set the full screen browsing mode preference icon.
455 fullScreenBrowsingModePreference.setIcon(R.drawable.full_screen_enabled)
457 // Set the hide app bar icon.
458 if (sharedPreferences.getBoolean(getString(R.string.hide_app_bar_key), true))
459 hideAppBarPreference.setIcon(R.drawable.app_bar_enabled)
461 hideAppBarPreference.setIcon(R.drawable.app_bar_disabled)
462 } else { // Full screen browsing mode is disabled.
464 fullScreenBrowsingModePreference.setIcon(R.drawable.full_screen_disabled)
465 hideAppBarPreference.setIcon(R.drawable.app_bar_ghosted)
468 // Set the clear everything icon.
469 if (clearEverything) {
470 clearEverythingPreference.setIcon(R.drawable.clear_everything_enabled)
472 clearEverythingPreference.setIcon(R.drawable.clear_everything_disabled)
475 // Set the clear cookies icon.
476 if (clearEverything || sharedPreferences.getBoolean(getString(R.string.clear_cookies_key), true))
477 clearCookiesPreference.setIcon(R.drawable.clear_cookies_enabled)
479 clearCookiesPreference.setIcon(R.drawable.clear_cookies_disabled)
481 // Set the clear DOM storage icon.
482 if (clearEverything || sharedPreferences.getBoolean(getString(R.string.clear_dom_storage_key), true))
483 clearDomStoragePreference.setIcon(R.drawable.clear_dom_storage_enabled)
485 clearDomStoragePreference.setIcon(R.drawable.clear_dom_storage_disabled)
487 // Set the clear form data icon if the API < 26. It has no effect on newer versions of Android.
488 if (Build.VERSION.SDK_INT < 26) {
489 if (clearEverything || sharedPreferences.getBoolean(getString(R.string.clear_form_data_key), true))
490 clearFormDataPreference.setIcon(R.drawable.clear_form_data_enabled)
492 clearFormDataPreference.setIcon(R.drawable.clear_form_data_disabled)
495 // Set the clear logcat icon.
496 if (clearEverything || sharedPreferences.getBoolean(getString(R.string.clear_logcat_key), true))
497 clearLogcatPreference.setIcon(R.drawable.clear_logcat_enabled)
499 clearLogcatPreference.setIcon(R.drawable.clear_logcat_disabled)
501 // Set the clear cache icon.
502 if (clearEverything || sharedPreferences.getBoolean(getString(R.string.clear_cache_key), true))
503 clearCachePreference.setIcon(R.drawable.clear_cache_enabled)
505 clearCachePreference.setIcon(R.drawable.clear_cache_disabled)
507 // Set the open intents in new tab icon.
508 if (sharedPreferences.getBoolean(getString(R.string.open_intents_in_new_tab_key), true))
509 openIntentsInNewTabPreference.setIcon(R.drawable.tab_enabled)
511 openIntentsInNewTabPreference.setIcon(R.drawable.tab_disabled)
513 // Set the swipe to refresh icon.
514 if (sharedPreferences.getBoolean(getString(R.string.swipe_to_refresh_key), true))
515 swipeToRefreshPreference.setIcon(R.drawable.refresh_enabled)
517 swipeToRefreshPreference.setIcon(R.drawable.refresh_disabled)
519 // Set the download with external app icon.
520 if (sharedPreferences.getBoolean(getString(R.string.download_with_external_app_key), false))
521 downloadWithExternalAppPreference.setIcon(R.drawable.download_with_external_app_enabled)
523 downloadWithExternalAppPreference.setIcon(R.drawable.download_with_external_app_disabled)
525 // Set the scroll app bar icon.
526 if (sharedPreferences.getBoolean(getString(R.string.scroll_app_bar_key), true))
527 scrollAppBarPreference.setIcon(R.drawable.app_bar_enabled)
529 scrollAppBarPreference.setIcon(R.drawable.app_bar_disabled)
531 // Set the bottom app bar icon.
532 if (sharedPreferences.getBoolean(getString(R.string.bottom_app_bar_key), false))
533 bottomAppBarPreference.setIcon(R.drawable.bottom_app_bar_enabled)
535 bottomAppBarPreference.setIcon(R.drawable.bottom_app_bar_disabled)
537 // Set the display additional app bar icons icon.
538 if (sharedPreferences.getBoolean(getString(R.string.display_additional_app_bar_icons_key), false))
539 displayAdditionalAppBarIconsPreference.setIcon(R.drawable.more_enabled)
541 displayAdditionalAppBarIconsPreference.setIcon(R.drawable.more_disabled)
543 // Set the WebView theme icon.
544 if (webViewThemePreference.isEnabled) { // The WebView theme preference is enabled.
545 when (webViewThemeEntryNumber) {
546 // The system default WebView theme is selected.
548 // Get the current theme status.
549 val currentThemeStatus = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
551 // Set the icon according to the app theme.
552 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO)
553 webViewThemePreference.setIcon(R.drawable.webview_light_theme)
555 webViewThemePreference.setIcon(R.drawable.webview_dark_theme)
558 // The light WebView theme is selected.
561 webViewThemePreference.setIcon(R.drawable.webview_light_theme)
564 // The dark WebView theme is selected.
567 webViewThemePreference.setIcon(R.drawable.webview_dark_theme)
570 } else { // The WebView theme preference is disabled.
571 webViewThemePreference.setIcon(R.drawable.webview_theme_ghosted)
574 // Set the wide viewport icon.
575 if (sharedPreferences.getBoolean(getString(R.string.wide_viewport_key), true))
576 wideViewportPreference.setIcon(R.drawable.wide_viewport_enabled)
578 wideViewportPreference.setIcon(R.drawable.wide_viewport_disabled)
580 // Set the display webpage images icon.
581 if (sharedPreferences.getBoolean(getString(R.string.display_webpage_images_key), true))
582 displayWebpageImagesPreference.setIcon(R.drawable.images_enabled)
584 displayWebpageImagesPreference.setIcon(R.drawable.images_disabled)
587 // The listener should be unregistered when the app is paused.
588 override fun onPause() {
589 // Run the default commands.
592 // Get a handle for the shared preferences.
593 val sharedPreferences = preferenceScreen.sharedPreferences!!
595 // Unregister the shared preference listener.
596 sharedPreferences.unregisterOnSharedPreferenceChangeListener(sharedPreferenceChangeListener)
599 // The listener should be re-registered when the app is resumed.
600 override fun onResume() {
601 // Run the default commands.
604 // Get a new shared preference change listener.
605 sharedPreferenceChangeListener = getSharedPreferenceChangeListener()
607 // Get a handle for the shared preferences.
608 val sharedPreferences = preferenceScreen.sharedPreferences!!
610 // Re-register the shared preference listener.
611 sharedPreferences.registerOnSharedPreferenceChangeListener(sharedPreferenceChangeListener)
613 // Restore the scroll position if the fragment has been restarted.
614 if (fragmentRestarted) {
615 // Reset the fragment restarted flag.
616 fragmentRestarted = false
618 // Set the scroll position.
619 listView.smoothScrollBy(0, scrollY)
623 override fun onSaveInstanceState(savedInstanceState: Bundle) {
624 // Run the default commands.
625 super.onSaveInstanceState(savedInstanceState)
627 // Save the scroll position.
628 savedInstanceState.putInt(SCROLL_Y, listView.computeVerticalScrollOffset())
631 private fun getSharedPreferenceChangeListener(): OnSharedPreferenceChangeListener {
632 // Return the shared preference change listener.
633 return OnSharedPreferenceChangeListener { sharedPreferences: SharedPreferences, key: String? ->
635 getString(R.string.javascript_key) -> {
636 // Update the icons and the DOM storage preference status.
637 if (sharedPreferences.getBoolean(getString(R.string.javascript_key), false)) { // The JavaScript preference is enabled.
638 // Update the icon for the JavaScript preference.
639 javaScriptPreference.setIcon(R.drawable.javascript_enabled)
641 // Update the status of the DOM storage preference.
642 domStoragePreference.isEnabled = true
644 // Update the icon for the DOM storage preference.
645 if (sharedPreferences.getBoolean(getString(R.string.dom_storage_key), false))
646 domStoragePreference.setIcon(R.drawable.dom_storage_enabled)
648 domStoragePreference.setIcon(R.drawable.dom_storage_disabled)
649 } else { // The JavaScript preference is disabled.
650 // Update the icon for the JavaScript preference.
651 javaScriptPreference.setIcon(R.drawable.privacy_mode)
653 // Update the status of the DOM storage preference.
654 domStoragePreference.isEnabled = false
656 // Set the icon for DOM storage preference to be ghosted.
657 domStoragePreference.setIcon(R.drawable.dom_storage_ghosted)
661 getString(R.string.cookies_key) -> {
663 if (sharedPreferences.getBoolean(getString(R.string.cookies_key), false))
664 cookiesPreference.setIcon(R.drawable.cookies_enabled)
666 cookiesPreference.setIcon(R.drawable.cookies_disabled)
669 getString(R.string.dom_storage_key) -> {
671 if (sharedPreferences.getBoolean(getString(R.string.dom_storage_key), false))
672 domStoragePreference.setIcon(R.drawable.dom_storage_enabled)
674 domStoragePreference.setIcon(R.drawable.dom_storage_disabled)
677 getString(R.string.save_form_data_key) -> { // Saved form data can be removed once the minimum API >= 26.
679 if (sharedPreferences.getBoolean(getString(R.string.save_form_data_key), false))
680 formDataPreference.setIcon(R.drawable.form_data_enabled)
682 formDataPreference.setIcon(R.drawable.form_data_disabled)
685 getString(R.string.user_agent_key) -> {
686 // Get the new user agent name.
687 val newUserAgentName = sharedPreferences.getString(getString(R.string.user_agent_key), getString(R.string.user_agent_default_value))
689 // Get the array position for the new user agent name.
690 val newUserAgentArrayPosition = userAgentNamesArray.getPosition(newUserAgentName)
692 // Get the translated new user agent name.
693 val translatedNewUserAgentName = translatedUserAgentNamesArray[newUserAgentArrayPosition]
695 // Populate the user agent summary.
696 when (newUserAgentArrayPosition) {
697 SETTINGS_WEBVIEW_DEFAULT_USER_AGENT -> {
698 // Get the user agent text from the webview (which changes based on the version of Android and WebView installed).
699 userAgentPreference.summary = "$translatedNewUserAgentName:\n$defaultUserAgent"
701 // Disable the custom user agent preference.
702 customUserAgentPreference.isEnabled = false
704 // Set the custom user agent preference icon.
705 customUserAgentPreference.setIcon(R.drawable.custom_user_agent_ghosted)
708 SETTINGS_CUSTOM_USER_AGENT -> {
709 // Set the summary text.
710 userAgentPreference.setSummary(R.string.custom_user_agent)
712 // Enable the custom user agent preference.
713 customUserAgentPreference.isEnabled = true
715 // Set the custom user agent preference icon.
716 customUserAgentPreference.setIcon(R.drawable.custom_user_agent_enabled)
720 // Get the user agent summary from the user agent data array.
721 userAgentPreference.summary = "$translatedNewUserAgentName:\n${userAgentDataArray[newUserAgentArrayPosition]}"
723 // Disable the custom user agent preference.
724 customUserAgentPreference.isEnabled = false
726 // Set the custom user agent preference icon.
727 customUserAgentPreference.setIcon(R.drawable.custom_user_agent_ghosted)
732 getString(R.string.custom_user_agent_key) -> {
733 // Set the new custom user agent as the summary text for the preference.
734 customUserAgentPreference.summary = sharedPreferences.getString(getString(R.string.custom_user_agent_key), getString(R.string.custom_user_agent_default_value))
737 getString(R.string.incognito_mode_key) -> {
739 if (sharedPreferences.getBoolean(getString(R.string.incognito_mode_key), false))
740 incognitoModePreference.setIcon(R.drawable.incognito_mode_enabled)
742 incognitoModePreference.setIcon(R.drawable.incognito_mode_disabled)
745 getString(R.string.allow_screenshots_key) -> {
747 if (sharedPreferences.getBoolean(getString(R.string.allow_screenshots_key), false))
748 allowScreenshotsPreference.setIcon(R.drawable.allow_screenshots_enabled)
750 allowScreenshotsPreference.setIcon(R.drawable.allow_screenshots_disabled)
752 // Restart Privacy Browser.
753 restartPrivacyBrowser()
756 getString(R.string.easylist_key) -> {
758 if (sharedPreferences.getBoolean(getString(R.string.easylist_key), true))
759 easyListPreference.setIcon(R.drawable.block_ads_enabled)
761 easyListPreference.setIcon(R.drawable.block_ads_disabled)
764 getString(R.string.easyprivacy_key) -> {
766 if (sharedPreferences.getBoolean(getString(R.string.easyprivacy_key), true))
767 easyPrivacyPreference.setIcon(R.drawable.block_tracking_enabled)
769 easyPrivacyPreference.setIcon(R.drawable.block_tracking_disabled)
772 getString(R.string.fanboys_annoyance_list_key) -> {
773 // Get the current Fanboy settings.
774 val currentFanboyAnnoyanceList = sharedPreferences.getBoolean(getString(R.string.fanboys_annoyance_list_key), true)
775 val currentFanboySocialBlockingList = sharedPreferences.getBoolean(getString(R.string.fanboys_social_blocking_list_key), true)
777 // Update the Fanboy icons.
778 if (currentFanboyAnnoyanceList) { // Fanboy's annoyance list is enabled.
779 // Update the Fanboy's annoyance list icon.
780 fanboyAnnoyanceListPreference.setIcon(R.drawable.social_media_enabled)
782 // Update the Fanboy's social blocking list icon.
783 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_ghosted)
784 } else { // Fanboy's annoyance list is disabled.
785 // Update the Fanboy's annoyance list icon.
786 fanboyAnnoyanceListPreference.setIcon(R.drawable.social_media_disabled)
788 // Update the Fanboy's social blocking list icon.
789 if (currentFanboySocialBlockingList)
790 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_enabled)
792 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_disabled)
795 // Only enable Fanboy's social blocking list preference if Fanboy's annoyance list preference is disabled.
796 fanboySocialBlockingListPreference.isEnabled = !currentFanboyAnnoyanceList
799 getString(R.string.fanboys_social_blocking_list_key) -> {
801 if (sharedPreferences.getBoolean(getString(R.string.fanboys_social_blocking_list_key), true))
802 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_enabled)
804 fanboySocialBlockingListPreference.setIcon(R.drawable.social_media_disabled)
807 getString(R.string.ultralist_key) -> {
809 if (sharedPreferences.getBoolean(getString(R.string.ultralist_key), true))
810 ultraListPreference.setIcon(R.drawable.block_ads_enabled)
812 ultraListPreference.setIcon(R.drawable.block_ads_disabled)
815 getString(R.string.ultraprivacy_key) -> {
817 if (sharedPreferences.getBoolean(getString(R.string.ultraprivacy_key), true))
818 ultraPrivacyPreference.setIcon(R.drawable.block_tracking_enabled)
820 ultraPrivacyPreference.setIcon(R.drawable.block_tracking_disabled)
823 getString(R.string.block_all_third_party_requests_key) -> {
825 if (sharedPreferences.getBoolean(getString(R.string.block_all_third_party_requests_key), false)) {
826 blockAllThirdPartyRequestsPreference.setIcon(R.drawable.block_all_third_party_requests_enabled)
828 blockAllThirdPartyRequestsPreference.setIcon(R.drawable.block_all_third_party_requests_disabled)
832 getString(R.string.tracking_queries_key) -> {
834 if (sharedPreferences.getBoolean(getString(R.string.tracking_queries_key), true))
835 trackingQueriesPreference.setIcon(R.drawable.modify_url_enabled)
837 trackingQueriesPreference.setIcon(R.drawable.modify_url_disabled)
840 getString(R.string.amp_redirects_key) -> {
842 if (sharedPreferences.getBoolean(getString(R.string.amp_redirects_key), true))
843 ampRedirectsPreference.setIcon(R.drawable.modify_url_enabled)
845 ampRedirectsPreference.setIcon(R.drawable.modify_url_disabled)
848 getString(R.string.search_key) -> {
849 // Store the new search string.
850 val newSearchString = sharedPreferences.getString(getString(R.string.search_key), getString(R.string.search_default_value))
852 // Update the search and search custom URL preferences.
853 if (newSearchString == getString(R.string.custom_url_item)) { // A custom URL is selected.
854 // Set the summary text to `R.string.custom_url`, which is translated.
855 searchPreference.setSummary(R.string.custom_url)
857 // Enable the search custom URL preference.
858 searchCustomURLPreference.isEnabled = true
860 // Set the search custom URL preference icon.
861 searchCustomURLPreference.setIcon(R.drawable.search_custom_enabled)
862 } else { // A custom URL is not selected.
863 // Set the summary text to the new search string.
864 searchPreference.summary = newSearchString
866 // Disable the search custom URL Preference.
867 searchCustomURLPreference.isEnabled = false
869 // Set the search custom URL preference icon.
870 searchCustomURLPreference.setIcon(R.drawable.search_custom_ghosted)
874 getString(R.string.search_custom_url_key) -> {
875 // Set the new search custom URL as the summary text for the preference.
876 searchCustomURLPreference.summary = sharedPreferences.getString(getString(R.string.search_custom_url_key), getString(R.string.search_custom_url_default_value))
879 getString(R.string.proxy_key) -> {
880 // Get the current proxy string.
881 val currentProxyString = sharedPreferences.getString(getString(R.string.proxy_key), getString(R.string.proxy_default_value))
883 // Update the proxy preference summary text.
884 proxyPreference.summary = when (currentProxyString) {
885 ProxyHelper.NONE -> getString(R.string.no_proxy_enabled)
886 ProxyHelper.TOR -> getString(R.string.tor_enabled)
887 ProxyHelper.I2P -> getString(R.string.i2p_enabled)
888 ProxyHelper.CUSTOM -> getString(R.string.custom_proxy)
889 else -> getString(R.string.no_proxy_enabled)
892 // Update the status of the custom URL preference.
893 proxyCustomUrlPreference.isEnabled = currentProxyString == ProxyHelper.CUSTOM
896 if (currentProxyString == ProxyHelper.NONE) { // Proxying is disabled.
897 // Set the main proxy icon to be disabled
898 proxyPreference.setIcon(R.drawable.proxy_disabled)
900 // Set the custom proxy URL icon to be ghosted.
901 proxyCustomUrlPreference.setIcon(R.drawable.proxy_ghosted)
902 } else { // Proxying is enabled.
903 // Set the main proxy icon to be enabled.
904 proxyPreference.setIcon(R.drawable.proxy_enabled)
906 /// Set the custom proxy URL icon according to its status.
907 if (proxyCustomUrlPreference.isEnabled)
908 proxyCustomUrlPreference.setIcon(R.drawable.proxy_enabled)
910 proxyCustomUrlPreference.setIcon(R.drawable.proxy_ghosted)
914 getString(R.string.proxy_custom_url_key) -> {
915 // Set the summary text for the proxy custom URL.
916 proxyCustomUrlPreference.summary = sharedPreferences.getString(getString(R.string.proxy_custom_url_key), getString(R.string.proxy_custom_url_default_value))
919 getString(R.string.full_screen_browsing_mode_key) -> {
921 if (sharedPreferences.getBoolean(getString(R.string.full_screen_browsing_mode_key), false)) { // Full screen browsing is enabled.
922 // Set the full screen browsing mode preference icon.
923 fullScreenBrowsingModePreference.setIcon(R.drawable.full_screen_enabled)
925 // Set the hide app bar preference icon.
926 if (sharedPreferences.getBoolean(getString(R.string.hide_app_bar_key), true))
927 hideAppBarPreference.setIcon(R.drawable.app_bar_enabled)
929 hideAppBarPreference.setIcon(R.drawable.app_bar_disabled)
930 } else { // Full screen browsing is disabled.
932 fullScreenBrowsingModePreference.setIcon(R.drawable.full_screen_disabled)
933 hideAppBarPreference.setIcon(R.drawable.app_bar_ghosted)
937 getString(R.string.hide_app_bar_key) -> {
939 if (sharedPreferences.getBoolean(getString(R.string.hide_app_bar_key), true))
940 hideAppBarPreference.setIcon(R.drawable.app_bar_enabled)
942 hideAppBarPreference.setIcon(R.drawable.app_bar_disabled)
945 getString(R.string.clear_everything_key) -> {
946 // Store the new clear everything status
947 val newClearEverythingBoolean = sharedPreferences.getBoolean(getString(R.string.clear_everything_key), true)
949 // Update the status of the clear and exit preferences.
950 clearCookiesPreference.isEnabled = !newClearEverythingBoolean
951 clearDomStoragePreference.isEnabled = !newClearEverythingBoolean
952 clearFormDataPreference.isEnabled = !newClearEverythingBoolean // Clear form data can be removed once the minimum API >= 26.
953 clearLogcatPreference.isEnabled = !newClearEverythingBoolean
954 clearCachePreference.isEnabled = !newClearEverythingBoolean
956 // Update the clear everything preference icon.
957 if (newClearEverythingBoolean)
958 clearEverythingPreference.setIcon(R.drawable.clear_everything_enabled)
960 clearEverythingPreference.setIcon(R.drawable.clear_everything_disabled)
962 // Update the clear cookies preference icon.
963 if (newClearEverythingBoolean || 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)
968 // Update the clear dom storage preference icon.
969 if (newClearEverythingBoolean || sharedPreferences.getBoolean(getString(R.string.clear_dom_storage_key), true))
970 clearDomStoragePreference.setIcon(R.drawable.clear_dom_storage_enabled)
972 clearDomStoragePreference.setIcon(R.drawable.clear_dom_storage_disabled)
974 // Update the clear form data preference icon if the API < 26.
975 if (Build.VERSION.SDK_INT < 26) {
976 if (newClearEverythingBoolean || sharedPreferences.getBoolean(getString(R.string.clear_form_data_key), true))
977 clearFormDataPreference.setIcon(R.drawable.clear_form_data_enabled)
979 clearFormDataPreference.setIcon(R.drawable.clear_form_data_disabled)
982 // Update the clear logcat preference icon.
983 if (newClearEverythingBoolean || sharedPreferences.getBoolean(getString(R.string.clear_logcat_key), true))
984 clearLogcatPreference.setIcon(R.drawable.clear_logcat_enabled)
986 clearLogcatPreference.setIcon(R.drawable.clear_logcat_disabled)
988 // Update the clear cache preference icon.
989 if (newClearEverythingBoolean || sharedPreferences.getBoolean(getString(R.string.clear_cache_key), true))
990 clearCachePreference.setIcon(R.drawable.clear_cache_enabled)
992 clearCachePreference.setIcon(R.drawable.clear_cache_disabled)
995 getString(R.string.clear_cookies_key) -> {
997 if (sharedPreferences.getBoolean(getString(R.string.clear_cookies_key), true))
998 clearCookiesPreference.setIcon(R.drawable.clear_cookies_enabled)
1000 clearCookiesPreference.setIcon(R.drawable.clear_cookies_disabled)
1003 getString(R.string.clear_dom_storage_key) -> {
1005 if (sharedPreferences.getBoolean(getString(R.string.clear_dom_storage_key), true))
1006 clearDomStoragePreference.setIcon(R.drawable.clear_dom_storage_enabled)
1008 clearDomStoragePreference.setIcon(R.drawable.clear_dom_storage_disabled)
1011 getString(R.string.clear_form_data_key) -> {
1013 if (sharedPreferences.getBoolean(getString(R.string.clear_form_data_key), true))
1014 clearFormDataPreference.setIcon(R.drawable.clear_form_data_enabled)
1016 clearFormDataPreference.setIcon(R.drawable.clear_form_data_disabled)
1019 getString(R.string.clear_logcat_key) -> {
1021 if (sharedPreferences.getBoolean(getString(R.string.clear_logcat_key), true))
1022 clearLogcatPreference.setIcon(R.drawable.clear_logcat_enabled)
1024 clearLogcatPreference.setIcon(R.drawable.clear_logcat_disabled)
1027 getString(R.string.clear_cache_key) -> {
1029 if (sharedPreferences.getBoolean(getString(R.string.clear_cache_key), true))
1030 clearCachePreference.setIcon(R.drawable.clear_cache_enabled)
1032 clearCachePreference.setIcon(R.drawable.clear_cache_disabled)
1035 getString(R.string.homepage_key) -> {
1036 // Set the new homepage URL as the summary text for the Homepage preference.
1037 homepagePreference.summary = sharedPreferences.getString(getString(R.string.homepage_key), getString(R.string.homepage_default_value))
1040 getString(R.string.font_size_key) -> {
1041 // Update the font size summary text.
1042 fontSizePreference.summary = sharedPreferences.getString(getString(R.string.font_size_key), getString(R.string.font_size_default_value)) + "%"
1045 getString(R.string.open_intents_in_new_tab_key) -> {
1047 if (sharedPreferences.getBoolean(getString(R.string.open_intents_in_new_tab_key), true))
1048 openIntentsInNewTabPreference.setIcon(R.drawable.tab_enabled)
1050 openIntentsInNewTabPreference.setIcon(R.drawable.tab_disabled)
1053 getString(R.string.swipe_to_refresh_key) -> {
1055 if (sharedPreferences.getBoolean(getString(R.string.swipe_to_refresh_key), true))
1056 swipeToRefreshPreference.setIcon(R.drawable.refresh_enabled)
1058 swipeToRefreshPreference.setIcon(R.drawable.refresh_disabled)
1061 getString(R.string.download_with_external_app_key) -> {
1063 if (sharedPreferences.getBoolean(getString(R.string.download_with_external_app_key), false))
1064 downloadWithExternalAppPreference.setIcon(R.drawable.download_with_external_app_enabled)
1066 downloadWithExternalAppPreference.setIcon(R.drawable.download_with_external_app_disabled)
1069 getString(R.string.scroll_app_bar_key) -> {
1071 if (sharedPreferences.getBoolean(getString(R.string.scroll_app_bar_key), true))
1072 scrollAppBarPreference.setIcon(R.drawable.app_bar_enabled)
1074 scrollAppBarPreference.setIcon(R.drawable.app_bar_disabled)
1077 getString(R.string.bottom_app_bar_key) -> {
1079 if (sharedPreferences.getBoolean(getString(R.string.bottom_app_bar_key), false))
1080 bottomAppBarPreference.setIcon(R.drawable.bottom_app_bar_enabled)
1082 bottomAppBarPreference.setIcon(R.drawable.bottom_app_bar_disabled)
1084 // Restart Privacy Browser.
1085 restartPrivacyBrowser()
1088 getString(R.string.display_additional_app_bar_icons_key) -> {
1090 if (sharedPreferences.getBoolean(getString(R.string.display_additional_app_bar_icons_key), false))
1091 displayAdditionalAppBarIconsPreference.setIcon(R.drawable.more_enabled)
1093 displayAdditionalAppBarIconsPreference.setIcon(R.drawable.more_disabled)
1095 // Restart Privacy Browser.
1096 restartPrivacyBrowser()
1099 getString(R.string.app_theme_key) -> {
1100 // Get the app theme entry number that matches the current app theme.
1101 val appThemeEntryNumber: Int = when (sharedPreferences.getString(getString(R.string.app_theme_key), getString(R.string.app_theme_default_value))) {
1102 appThemeEntryValuesStringArray[1] -> 1 // The light theme is selected.
1103 appThemeEntryValuesStringArray[2] -> 2 // The dark theme is selected.
1104 else -> 0 // The system default theme is selected.
1107 // Update the system according to the new theme.
1108 when (appThemeEntryNumber) {
1109 0 -> { // The system default theme is selected.
1110 // Update the theme preference summary text.
1111 appThemePreference.summary = appThemeEntriesStringArray[0]
1113 // Apply the new theme.
1114 if (Build.VERSION.SDK_INT >= 28) { // The system default theme is supported.
1115 // Follow the system default theme.
1116 AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
1117 } else { // The system default theme is not supported.
1118 // Follow the battery saver mode.
1119 AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_AUTO_BATTERY)
1123 1 -> { // The light theme is selected.
1124 // Update the theme preference summary text.
1125 appThemePreference.summary = appThemeEntriesStringArray[1]
1127 // Apply the new theme.
1128 AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
1131 2 -> { // The dark theme is selected.
1132 // Update the theme preference summary text.
1133 appThemePreference.summary = appThemeEntriesStringArray[2]
1135 // Apply the new theme.
1136 AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
1140 // Enable the WebView theme preference if the app theme is not set to light. Google does not allow light themes to display dark WebViews.
1141 webViewThemePreference.isEnabled = (appThemeEntryNumber != 1)
1143 // Get the webView theme entry number that matches the new WebView theme.
1144 val webViewThemeEntryNumber: Int = when (sharedPreferences.getString(getString(R.string.webview_theme_key), getString(R.string.webview_theme_default_value))) {
1145 webViewThemeEntriesStringArray[1] -> 1 // The light theme is selected.
1146 webViewThemeEntryValuesStringArray[2] -> 2 // The dark theme is selected.
1147 else -> 0 // The system default theme is selected.
1150 // Update the WebView theme icon.
1151 if (webViewThemePreference.isEnabled) { // The WebView theme preference is enabled.
1152 when (webViewThemeEntryNumber) {
1153 // The system default WebView theme is selected.
1155 // Get the current theme status.
1156 val currentThemeStatus = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
1158 // Set the icon according to the app theme.
1159 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO)
1160 webViewThemePreference.setIcon(R.drawable.webview_light_theme)
1162 webViewThemePreference.setIcon(R.drawable.webview_dark_theme)
1165 // The light WebView theme is selected.
1168 webViewThemePreference.setIcon(R.drawable.webview_light_theme)
1171 // The dark WebView theme is selected.
1174 webViewThemePreference.setIcon(R.drawable.webview_dark_theme)
1177 } else { // The WebView theme preference is disabled.
1178 webViewThemePreference.setIcon(R.drawable.webview_theme_ghosted)
1182 getString(R.string.webview_theme_key) -> {
1183 // Get the webView theme entry number that matches the new WebView theme.
1184 val newWebViewThemeEntryNumber: Int = when (sharedPreferences.getString(getString(R.string.webview_theme_key), getString(R.string.webview_theme_default_value))) {
1185 webViewThemeEntriesStringArray[1] -> 1 // The light theme is selected.
1186 webViewThemeEntryValuesStringArray[2] -> 2 // The dark theme is selected.
1187 else -> 0 // The system default theme is selected.
1190 // Update the WebView theme icon.
1191 when (newWebViewThemeEntryNumber) {
1192 // The system default WebView theme is selected.
1194 // Get the current theme status.
1195 val currentThemeStatus = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
1198 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO)
1199 webViewThemePreference.setIcon(R.drawable.webview_light_theme)
1201 webViewThemePreference.setIcon(R.drawable.webview_dark_theme)
1204 // The light WebView theme is selected.
1207 webViewThemePreference.setIcon(R.drawable.webview_light_theme)
1210 // The dark WebView theme is selected.
1213 webViewThemePreference.setIcon(R.drawable.webview_dark_theme)
1217 // Set the current theme as the summary text for the preference.
1218 webViewThemePreference.summary = webViewThemeEntriesStringArray[newWebViewThemeEntryNumber]
1221 getString(R.string.wide_viewport_key) -> {
1223 if (sharedPreferences.getBoolean(getString(R.string.wide_viewport_key), true))
1224 wideViewportPreference.setIcon(R.drawable.wide_viewport_enabled)
1226 wideViewportPreference.setIcon(R.drawable.wide_viewport_disabled)
1229 getString(R.string.display_webpage_images_key) -> {
1231 if (sharedPreferences.getBoolean(getString(R.string.display_webpage_images_key), true))
1232 displayWebpageImagesPreference.setIcon(R.drawable.images_enabled)
1234 displayWebpageImagesPreference.setIcon(R.drawable.images_disabled)
1240 private fun restartPrivacyBrowser() {
1241 // Create an intent to restart Privacy Browser.
1242 val restartIntent = requireActivity().parentActivityIntent!!
1244 // `Intent.FLAG_ACTIVITY_CLEAR_TASK` removes all activities from the stack. It requires `Intent.FLAG_ACTIVITY_NEW_TASK`.
1245 restartIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
1247 // Create a handler to restart the activity.
1248 val restartHandler = Handler(Looper.getMainLooper())
1250 // Create a runnable to restart the activity.
1251 val restartRunnable = Runnable {
1252 // Restart the activity.
1253 startActivity(restartIntent)
1255 // Kill this instance of Privacy Browser. Otherwise, the app exhibits sporadic behavior after the restart.
1259 // Restart the activity after 400 milliseconds, so that the app has enough time to save the change to the preference.
1260 restartHandler.postDelayed(restartRunnable, 400)