]> gitweb.stoutner.com Git - PrivacyBrowserAndroid.git/blob - app/src/main/java/com/stoutner/privacybrowser/fragments/DomainSettingsFragment.kt
First wrong button text in View Headers in night theme. https://redmine.stoutner...
[PrivacyBrowserAndroid.git] / app / src / main / java / com / stoutner / privacybrowser / fragments / DomainSettingsFragment.kt
1 /*
2  * Copyright 2017-2024 Soren Stoutner <soren@stoutner.com>.
3  *
4  * This file is part of Privacy Browser Android <https://www.stoutner.com/privacy-browser-android>.
5  *
6  * Privacy Browser Android is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * Privacy Browser Android is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with Privacy Browser Android.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 package com.stoutner.privacybrowser.fragments
21
22 import android.annotation.SuppressLint
23 import android.content.Context
24 import android.content.res.Configuration
25 import android.os.Bundle
26 import android.text.Editable
27 import android.text.SpannableStringBuilder
28 import android.text.Spanned
29 import android.text.TextWatcher
30 import android.text.style.ForegroundColorSpan
31 import android.view.LayoutInflater
32 import android.view.View
33 import android.view.ViewGroup
34 import android.webkit.WebView
35 import android.widget.AdapterView
36 import android.widget.ArrayAdapter
37 import android.widget.CompoundButton
38 import android.widget.EditText
39 import android.widget.ImageView
40 import android.widget.LinearLayout
41 import android.widget.RadioButton
42 import android.widget.ScrollView
43 import android.widget.Spinner
44 import android.widget.TextView
45
46 import androidx.appcompat.widget.SwitchCompat
47 import androidx.cardview.widget.CardView
48 import androidx.core.content.ContextCompat.getColor
49 import androidx.core.content.res.ResourcesCompat
50 import androidx.fragment.app.Fragment
51 import androidx.preference.PreferenceManager
52
53 import com.stoutner.privacybrowser.R
54 import com.stoutner.privacybrowser.activities.DOMAINS_CUSTOM_USER_AGENT
55 import com.stoutner.privacybrowser.activities.DOMAINS_SYSTEM_DEFAULT_USER_AGENT
56 import com.stoutner.privacybrowser.activities.DOMAINS_WEBVIEW_DEFAULT_USER_AGENT
57 import com.stoutner.privacybrowser.activities.SETTINGS_CUSTOM_USER_AGENT
58 import com.stoutner.privacybrowser.activities.SETTINGS_WEBVIEW_DEFAULT_USER_AGENT
59 import com.stoutner.privacybrowser.activities.UNRECOGNIZED_USER_AGENT
60 import com.stoutner.privacybrowser.activities.DomainsActivity
61 import com.stoutner.privacybrowser.helpers.BLOCK_ALL_THIRD_PARTY_REQUESTS
62 import com.stoutner.privacybrowser.helpers.COOKIES
63 import com.stoutner.privacybrowser.helpers.DARK_THEME
64 import com.stoutner.privacybrowser.helpers.DISABLED
65 import com.stoutner.privacybrowser.helpers.DISPLAY_IMAGES
66 import com.stoutner.privacybrowser.helpers.DOMAIN_NAME
67 import com.stoutner.privacybrowser.helpers.ENABLED
68 import com.stoutner.privacybrowser.helpers.LIGHT_THEME
69 import com.stoutner.privacybrowser.helpers.SYSTEM_DEFAULT
70 import com.stoutner.privacybrowser.helpers.ENABLE_DOM_STORAGE
71 import com.stoutner.privacybrowser.helpers.ENABLE_EASYLIST
72 import com.stoutner.privacybrowser.helpers.ENABLE_EASYPRIVACY
73 import com.stoutner.privacybrowser.helpers.ENABLE_FANBOYS_ANNOYANCE_LIST
74 import com.stoutner.privacybrowser.helpers.ENABLE_FANBOYS_SOCIAL_BLOCKING_LIST
75 import com.stoutner.privacybrowser.helpers.ENABLE_JAVASCRIPT
76 import com.stoutner.privacybrowser.helpers.ENABLE_ULTRAPRIVACY
77 import com.stoutner.privacybrowser.helpers.FONT_SIZE
78 import com.stoutner.privacybrowser.helpers.IP_ADDRESSES
79 import com.stoutner.privacybrowser.helpers.PINNED_IP_ADDRESSES
80 import com.stoutner.privacybrowser.helpers.PINNED_SSL_CERTIFICATE
81 import com.stoutner.privacybrowser.helpers.SSL_END_DATE
82 import com.stoutner.privacybrowser.helpers.SSL_ISSUED_BY_COMMON_NAME
83 import com.stoutner.privacybrowser.helpers.SSL_ISSUED_BY_ORGANIZATION
84 import com.stoutner.privacybrowser.helpers.SSL_ISSUED_BY_ORGANIZATIONAL_UNIT
85 import com.stoutner.privacybrowser.helpers.SSL_ISSUED_TO_COMMON_NAME
86 import com.stoutner.privacybrowser.helpers.SSL_ISSUED_TO_ORGANIZATION
87 import com.stoutner.privacybrowser.helpers.SSL_ISSUED_TO_ORGANIZATIONAL_UNIT
88 import com.stoutner.privacybrowser.helpers.SSL_START_DATE
89 import com.stoutner.privacybrowser.helpers.SWIPE_TO_REFRESH
90 import com.stoutner.privacybrowser.helpers.ULTRALIST
91 import com.stoutner.privacybrowser.helpers.USER_AGENT
92 import com.stoutner.privacybrowser.helpers.WEBVIEW_THEME
93 import com.stoutner.privacybrowser.helpers.WIDE_VIEWPORT
94 import com.stoutner.privacybrowser.helpers.DomainsDatabaseHelper
95
96 import java.lang.IndexOutOfBoundsException
97 import java.text.DateFormat
98 import java.util.Calendar
99 import java.util.Date
100
101 class DomainSettingsFragment : Fragment() {
102     // Define the class variables.
103     private var scrollY = 0
104
105     // Declare the class variables.
106     private lateinit var context: Context
107
108     companion object {
109         // Define the public constants.
110         const val DATABASE_ID = "database_id"
111         const val SCROLL_Y = "scroll_y"
112
113         // Define the public variables.  `databaseId` is public so it can be accessed from `DomainsActivity`.
114         var databaseId = 0
115     }
116
117     override fun onCreate(savedInstanceState: Bundle?) {
118         // Run the default commands.
119         super.onCreate(savedInstanceState)
120
121         // Store the arguments in class variables.
122         databaseId = requireArguments().getInt(DATABASE_ID)
123         scrollY = requireArguments().getInt(SCROLL_Y)
124     }
125
126     override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
127         // Inflate the layout.  The fragment will take care of attaching the root automatically.
128         val domainSettingsView = inflater.inflate(R.layout.domain_settings_fragment, container, false)
129
130         // Get a handle for the context.
131         context = requireContext()
132
133         // Get the current theme status.
134         val currentThemeStatus = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
135
136         // Get a handle for the shared preference.
137         val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
138
139         // Get the default values.
140         val javaScriptDefault = sharedPreferences.getBoolean(getString(R.string.javascript_key), false)
141         val cookiesDefault = sharedPreferences.getBoolean(getString(R.string.cookies_key), false)
142         val domStorageDefault = sharedPreferences.getBoolean(getString(R.string.dom_storage_key), false)
143         val userAgentDefault = sharedPreferences.getString(getString(R.string.user_agent_key), getString(R.string.user_agent_default_value))
144         val customUserAgentStringDefault = sharedPreferences.getString(getString(R.string.custom_user_agent_key), getString(R.string.custom_user_agent_default_value))
145         val easyListDefault = sharedPreferences.getBoolean(getString(R.string.easylist_key), true)
146         val easyPrivacyDefault = sharedPreferences.getBoolean(getString(R.string.easyprivacy_key), true)
147         val fanboysAnnoyanceListDefault = sharedPreferences.getBoolean(getString(R.string.fanboys_annoyance_list_key), true)
148         val fanboysSocialBlockingListDefault = sharedPreferences.getBoolean(getString(R.string.fanboys_social_blocking_list_key), true)
149         val ultraListDefault = sharedPreferences.getBoolean(getString(R.string.ultralist_key), true)
150         val ultraPrivacyDefault = sharedPreferences.getBoolean(getString(R.string.ultraprivacy_key), true)
151         val blockAllThirdPartyRequestsDefault = sharedPreferences.getBoolean(getString(R.string.block_all_third_party_requests_key), false)
152         val fontSizeStringDefault = sharedPreferences.getString(getString(R.string.font_size_key), getString(R.string.font_size_default_value))
153         val swipeToRefreshDefault = sharedPreferences.getBoolean(getString(R.string.swipe_to_refresh_key), true)
154         val webViewThemeDefault = sharedPreferences.getString(getString(R.string.webview_theme_key), getString(R.string.webview_theme_default_value))
155         val wideViewportDefault = sharedPreferences.getBoolean(getString(R.string.wide_viewport_key), true)
156         val displayWebpageImagesDefault = sharedPreferences.getBoolean(getString(R.string.display_webpage_images_key), true)
157
158         // Get handles for the views.
159         val domainSettingsScrollView = domainSettingsView.findViewById<ScrollView>(R.id.domain_settings_scrollview)
160         val domainNameEditText = domainSettingsView.findViewById<EditText>(R.id.domain_settings_name_edittext)
161         val javaScriptLinearLayout = domainSettingsView.findViewById<LinearLayout>(R.id.javascript_linearlayout)
162         val javaScriptImageView = domainSettingsView.findViewById<ImageView>(R.id.javascript_imageview)
163         val javaScriptSpinner = domainSettingsView.findViewById<Spinner>(R.id.javascript_spinner)
164         val javaScriptTextView = domainSettingsView.findViewById<TextView>(R.id.javascript_textview)
165         val cookiesLinearLayout = domainSettingsView.findViewById<LinearLayout>(R.id.cookies_linearlayout)
166         val cookiesImageView = domainSettingsView.findViewById<ImageView>(R.id.cookies_imageview)
167         val cookiesSpinner = domainSettingsView.findViewById<Spinner>(R.id.cookies_spinner)
168         val cookiesTextView = domainSettingsView.findViewById<TextView>(R.id.cookies_textview)
169         val domStorageLinearLayout = domainSettingsView.findViewById<LinearLayout>(R.id.dom_storage_linearlayout)
170         val domStorageImageView = domainSettingsView.findViewById<ImageView>(R.id.dom_storage_imageview)
171         val domStorageSpinner = domainSettingsView.findViewById<Spinner>(R.id.dom_storage_spinner)
172         val domStorageTextView = domainSettingsView.findViewById<TextView>(R.id.dom_storage_textview)
173         val userAgentLinearLayout = domainSettingsView.findViewById<LinearLayout>(R.id.user_agent_linearlayout)
174         val userAgentSpinner = domainSettingsView.findViewById<Spinner>(R.id.user_agent_spinner)
175         val userAgentTextView = domainSettingsView.findViewById<TextView>(R.id.user_agent_textview)
176         val customUserAgentEditText = domainSettingsView.findViewById<EditText>(R.id.custom_user_agent_edittext)
177         val easyListLinearLayout = domainSettingsView.findViewById<LinearLayout>(R.id.easylist_linearlayout)
178         val easyListImageView = domainSettingsView.findViewById<ImageView>(R.id.easylist_imageview)
179         val easyListSpinner = domainSettingsView.findViewById<Spinner>(R.id.easylist_spinner)
180         val easyListTextView = domainSettingsView.findViewById<TextView>(R.id.easylist_textview)
181         val easyPrivacyLinearLayout = domainSettingsView.findViewById<LinearLayout>(R.id.easyprivacy_linearlayout)
182         val easyPrivacyImageView = domainSettingsView.findViewById<ImageView>(R.id.easyprivacy_imageview)
183         val easyPrivacySpinner = domainSettingsView.findViewById<Spinner>(R.id.easyprivacy_spinner)
184         val easyPrivacyTextView = domainSettingsView.findViewById<TextView>(R.id.easyprivacy_textview)
185         val fanboysAnnoyanceListLinearLayout = domainSettingsView.findViewById<LinearLayout>(R.id.fanboys_annoyance_list_linearlayout)
186         val fanboysAnnoyanceListImageView = domainSettingsView.findViewById<ImageView>(R.id.fanboys_annoyance_list_imageview)
187         val fanboysAnnoyanceListSpinner = domainSettingsView.findViewById<Spinner>(R.id.fanboys_annoyance_list_spinner)
188         val fanboysAnnoyanceListTextView = domainSettingsView.findViewById<TextView>(R.id.fanboys_annoyance_list_textview)
189         val fanboysSocialBlockingListLinearLayout = domainSettingsView.findViewById<LinearLayout>(R.id.fanboys_social_blocking_list_linearlayout)
190         val fanboysSocialBlockingListImageView = domainSettingsView.findViewById<ImageView>(R.id.fanboys_social_blocking_list_imageview)
191         val fanboysSocialBlockingListSpinner = domainSettingsView.findViewById<Spinner>(R.id.fanboys_social_blocking_list_spinner)
192         val fanboysSocialBlockingListTextView = domainSettingsView.findViewById<TextView>(R.id.fanboys_social_blocking_list_textview)
193         val ultraListLinearLayout = domainSettingsView.findViewById<LinearLayout>(R.id.ultralist_linearlayout)
194         val ultraListImageView = domainSettingsView.findViewById<ImageView>(R.id.ultralist_imageview)
195         val ultraListSpinner = domainSettingsView.findViewById<Spinner>(R.id.ultralist_spinner)
196         val ultraListTextView = domainSettingsView.findViewById<TextView>(R.id.ultralist_textview)
197         val ultraPrivacyLinearLayout = domainSettingsView.findViewById<LinearLayout>(R.id.ultraprivacy_linearlayout)
198         val ultraPrivacyImageView = domainSettingsView.findViewById<ImageView>(R.id.ultraprivacy_imageview)
199         val ultraPrivacySpinner = domainSettingsView.findViewById<Spinner>(R.id.ultraprivacy_spinner)
200         val ultraPrivacyTextView = domainSettingsView.findViewById<TextView>(R.id.ultraprivacy_textview)
201         val blockAllThirdPartyRequestsLinearLayout = domainSettingsView.findViewById<LinearLayout>(R.id.block_all_third_party_requests_linearlayout)
202         val blockAllThirdPartyRequestsImageView = domainSettingsView.findViewById<ImageView>(R.id.block_all_third_party_requests_imageview)
203         val blockAllThirdPartyRequestsSpinner = domainSettingsView.findViewById<Spinner>(R.id.block_all_third_party_requests_spinner)
204         val blockAllThirdPartyRequestsTextView = domainSettingsView.findViewById<TextView>(R.id.block_all_third_party_requests_textview)
205         val fontSizeLinearLayout = domainSettingsView.findViewById<LinearLayout>(R.id.font_size_linearlayout)
206         val fontSizeSpinner = domainSettingsView.findViewById<Spinner>(R.id.font_size_spinner)
207         val defaultFontSizeTextView = domainSettingsView.findViewById<TextView>(R.id.default_font_size_textview)
208         val customFontSizeEditText = domainSettingsView.findViewById<EditText>(R.id.custom_font_size_edittext)
209         val swipeToRefreshLinearLayout = domainSettingsView.findViewById<LinearLayout>(R.id.swipe_to_refresh_linearlayout)
210         val swipeToRefreshImageView = domainSettingsView.findViewById<ImageView>(R.id.swipe_to_refresh_imageview)
211         val swipeToRefreshSpinner = domainSettingsView.findViewById<Spinner>(R.id.swipe_to_refresh_spinner)
212         val swipeToRefreshTextView = domainSettingsView.findViewById<TextView>(R.id.swipe_to_refresh_textview)
213         val webViewThemeLinearLayout = domainSettingsView.findViewById<LinearLayout>(R.id.webview_theme_linearlayout)
214         val webViewThemeImageView = domainSettingsView.findViewById<ImageView>(R.id.webview_theme_imageview)
215         val webViewThemeSpinner = domainSettingsView.findViewById<Spinner>(R.id.webview_theme_spinner)
216         val webViewThemeTextView = domainSettingsView.findViewById<TextView>(R.id.webview_theme_textview)
217         val wideViewportLinearLayout = domainSettingsView.findViewById<LinearLayout>(R.id.wide_viewport_linearlayout)
218         val wideViewportImageView = domainSettingsView.findViewById<ImageView>(R.id.wide_viewport_imageview)
219         val wideViewportSpinner = domainSettingsView.findViewById<Spinner>(R.id.wide_viewport_spinner)
220         val wideViewportTextView = domainSettingsView.findViewById<TextView>(R.id.wide_viewport_textview)
221         val displayImagesLinearLayout = domainSettingsView.findViewById<LinearLayout>(R.id.display_images_linearlayout)
222         val displayImagesImageView = domainSettingsView.findViewById<ImageView>(R.id.display_images_imageview)
223         val displayImagesSpinner = domainSettingsView.findViewById<Spinner>(R.id.display_images_spinner)
224         val displayImagesTextView = domainSettingsView.findViewById<TextView>(R.id.display_images_textview)
225         val pinnedSslCertificateImageView = domainSettingsView.findViewById<ImageView>(R.id.pinned_ssl_certificate_imageview)
226         val pinnedSslCertificateSwitch = domainSettingsView.findViewById<SwitchCompat>(R.id.pinned_ssl_certificate_switch)
227         val savedSslCardView = domainSettingsView.findViewById<CardView>(R.id.saved_ssl_certificate_cardview)
228         val savedSslCertificateLinearLayout = domainSettingsView.findViewById<LinearLayout>(R.id.saved_ssl_certificate_linearlayout)
229         val savedSslCertificateRadioButton = domainSettingsView.findViewById<RadioButton>(R.id.saved_ssl_certificate_radiobutton)
230         val savedSslIssuedToCNameTextView = domainSettingsView.findViewById<TextView>(R.id.saved_ssl_certificate_issued_to_cname)
231         val savedSslIssuedToONameTextView = domainSettingsView.findViewById<TextView>(R.id.saved_ssl_certificate_issued_to_oname)
232         val savedSslIssuedToUNameTextView = domainSettingsView.findViewById<TextView>(R.id.saved_ssl_certificate_issued_to_uname)
233         val savedSslIssuedByCNameTextView = domainSettingsView.findViewById<TextView>(R.id.saved_ssl_certificate_issued_by_cname)
234         val savedSslIssuedByONameTextView = domainSettingsView.findViewById<TextView>(R.id.saved_ssl_certificate_issued_by_oname)
235         val savedSslIssuedByUNameTextView = domainSettingsView.findViewById<TextView>(R.id.saved_ssl_certificate_issued_by_uname)
236         val savedSslStartDateTextView = domainSettingsView.findViewById<TextView>(R.id.saved_ssl_certificate_start_date)
237         val savedSslEndDateTextView = domainSettingsView.findViewById<TextView>(R.id.saved_ssl_certificate_end_date)
238         val currentSslCardView = domainSettingsView.findViewById<CardView>(R.id.current_website_certificate_cardview)
239         val currentWebsiteCertificateLinearLayout = domainSettingsView.findViewById<LinearLayout>(R.id.current_website_certificate_linearlayout)
240         val currentWebsiteCertificateRadioButton = domainSettingsView.findViewById<RadioButton>(R.id.current_website_certificate_radiobutton)
241         val currentSslIssuedToCNameTextView = domainSettingsView.findViewById<TextView>(R.id.current_website_certificate_issued_to_cname)
242         val currentSslIssuedToONameTextView = domainSettingsView.findViewById<TextView>(R.id.current_website_certificate_issued_to_oname)
243         val currentSslIssuedToUNameTextView = domainSettingsView.findViewById<TextView>(R.id.current_website_certificate_issued_to_uname)
244         val currentSslIssuedByCNameTextView = domainSettingsView.findViewById<TextView>(R.id.current_website_certificate_issued_by_cname)
245         val currentSslIssuedByONameTextView = domainSettingsView.findViewById<TextView>(R.id.current_website_certificate_issued_by_oname)
246         val currentSslIssuedByUNameTextView = domainSettingsView.findViewById<TextView>(R.id.current_website_certificate_issued_by_uname)
247         val currentSslStartDateTextView = domainSettingsView.findViewById<TextView>(R.id.current_website_certificate_start_date)
248         val currentSslEndDateTextView = domainSettingsView.findViewById<TextView>(R.id.current_website_certificate_end_date)
249         val noCurrentWebsiteCertificateTextView = domainSettingsView.findViewById<TextView>(R.id.no_current_website_certificate)
250         val pinnedIpAddressesImageView = domainSettingsView.findViewById<ImageView>(R.id.pinned_ip_addresses_imageview)
251         val pinnedIpAddressesSwitch = domainSettingsView.findViewById<SwitchCompat>(R.id.pinned_ip_addresses_switch)
252         val savedIpAddressesCardView = domainSettingsView.findViewById<CardView>(R.id.saved_ip_addresses_cardview)
253         val savedIpAddressesLinearLayout = domainSettingsView.findViewById<LinearLayout>(R.id.saved_ip_addresses_linearlayout)
254         val savedIpAddressesRadioButton = domainSettingsView.findViewById<RadioButton>(R.id.saved_ip_addresses_radiobutton)
255         val savedIpAddressesTextView = domainSettingsView.findViewById<TextView>(R.id.saved_ip_addresses_textview)
256         val currentIpAddressesCardView = domainSettingsView.findViewById<CardView>(R.id.current_ip_addresses_cardview)
257         val currentIpAddressesLinearLayout = domainSettingsView.findViewById<LinearLayout>(R.id.current_ip_addresses_linearlayout)
258         val currentIpAddressesRadioButton = domainSettingsView.findViewById<RadioButton>(R.id.current_ip_addresses_radiobutton)
259         val currentIpAddressesTextView = domainSettingsView.findViewById<TextView>(R.id.current_ip_addresses_textview)
260
261         // Initialize the database handler.
262         val domainsDatabaseHelper = DomainsDatabaseHelper(requireContext())
263
264         // Get the database cursor for this ID.
265         val domainCursor = domainsDatabaseHelper.getCursorForId(databaseId)
266
267         // Move to the first row.
268         domainCursor.moveToFirst()
269
270         // Save the cursor entries as variables.
271         val domainNameString = domainCursor.getString(domainCursor.getColumnIndexOrThrow(DOMAIN_NAME))
272         val javaScriptInt = domainCursor.getInt(domainCursor.getColumnIndexOrThrow(ENABLE_JAVASCRIPT))
273         val cookiesInt = domainCursor.getInt(domainCursor.getColumnIndexOrThrow(COOKIES))
274         val domStorageInt = domainCursor.getInt(domainCursor.getColumnIndexOrThrow(ENABLE_DOM_STORAGE))
275         val currentUserAgentName = domainCursor.getString(domainCursor.getColumnIndexOrThrow(USER_AGENT))
276         val easyListInt = domainCursor.getInt(domainCursor.getColumnIndexOrThrow(ENABLE_EASYLIST))
277         val easyPrivacyInt = domainCursor.getInt(domainCursor.getColumnIndexOrThrow(ENABLE_EASYPRIVACY))
278         val fanboysAnnoyanceListInt = domainCursor.getInt(domainCursor.getColumnIndexOrThrow(ENABLE_FANBOYS_ANNOYANCE_LIST))
279         val fanboysSocialBlockingListInt = domainCursor.getInt(domainCursor.getColumnIndexOrThrow(ENABLE_FANBOYS_SOCIAL_BLOCKING_LIST))
280         val ultraListInt = domainCursor.getInt(domainCursor.getColumnIndexOrThrow(ULTRALIST))
281         val ultraPrivacyInt = domainCursor.getInt(domainCursor.getColumnIndexOrThrow(ENABLE_ULTRAPRIVACY))
282         val blockAllThirdPartyRequestsInt = domainCursor.getInt(domainCursor.getColumnIndexOrThrow(BLOCK_ALL_THIRD_PARTY_REQUESTS))
283         val fontSizeInt = domainCursor.getInt(domainCursor.getColumnIndexOrThrow(FONT_SIZE))
284         val swipeToRefreshInt = domainCursor.getInt(domainCursor.getColumnIndexOrThrow(SWIPE_TO_REFRESH))
285         val webViewThemeInt = domainCursor.getInt(domainCursor.getColumnIndexOrThrow(WEBVIEW_THEME))
286         val wideViewportInt = domainCursor.getInt(domainCursor.getColumnIndexOrThrow(WIDE_VIEWPORT))
287         val displayImagesInt = domainCursor.getInt(domainCursor.getColumnIndexOrThrow(DISPLAY_IMAGES))
288         val pinnedSslCertificateInt = domainCursor.getInt(domainCursor.getColumnIndexOrThrow(PINNED_SSL_CERTIFICATE))
289         val savedSslIssuedToCNameString = domainCursor.getString(domainCursor.getColumnIndexOrThrow(SSL_ISSUED_TO_COMMON_NAME))
290         val savedSslIssuedToONameString = domainCursor.getString(domainCursor.getColumnIndexOrThrow(SSL_ISSUED_TO_ORGANIZATION))
291         val savedSslIssuedToUNameString = domainCursor.getString(domainCursor.getColumnIndexOrThrow(SSL_ISSUED_TO_ORGANIZATIONAL_UNIT))
292         val savedSslIssuedByCNameString = domainCursor.getString(domainCursor.getColumnIndexOrThrow(SSL_ISSUED_BY_COMMON_NAME))
293         val savedSslIssuedByONameString = domainCursor.getString(domainCursor.getColumnIndexOrThrow(SSL_ISSUED_BY_ORGANIZATION))
294         val savedSslIssuedByUNameString = domainCursor.getString(domainCursor.getColumnIndexOrThrow(SSL_ISSUED_BY_ORGANIZATIONAL_UNIT))
295         val savedSslStartDateLong = domainCursor.getLong(domainCursor.getColumnIndexOrThrow(SSL_START_DATE))
296         val savedSslEndDateLong = domainCursor.getLong(domainCursor.getColumnIndexOrThrow(SSL_END_DATE))
297         val pinnedIpAddressesInt = domainCursor.getInt(domainCursor.getColumnIndexOrThrow(PINNED_IP_ADDRESSES))
298         val savedIpAddresses = domainCursor.getString(domainCursor.getColumnIndexOrThrow(IP_ADDRESSES))
299
300         // Close the domain cursor.
301         domainCursor.close()
302
303         // Create spinner array adapters.
304         val javaScriptArrayAdapter = ArrayAdapter.createFromResource(context, R.array.javascript_array, R.layout.spinner_item)
305         val cookiesArrayAdapter = ArrayAdapter.createFromResource(context, R.array.cookies_array, R.layout.spinner_item)
306         val domStorageArrayAdapter = ArrayAdapter.createFromResource(context, R.array.dom_storage_array, R.layout.spinner_item)
307         val translatedUserAgentArrayAdapter = ArrayAdapter.createFromResource(context, R.array.translated_domain_settings_user_agent_names, R.layout.spinner_item)
308         val easyListArrayAdapter = ArrayAdapter.createFromResource(context, R.array.easylist_array, R.layout.spinner_item)
309         val easyPrivacyArrayAdapter = ArrayAdapter.createFromResource(context, R.array.easyprivacy_array, R.layout.spinner_item)
310         val fanboysAnnoyanceListArrayAdapter = ArrayAdapter.createFromResource(context, R.array.fanboys_annoyance_list_array, R.layout.spinner_item)
311         val fanboysSocialBlockingListArrayAdapter = ArrayAdapter.createFromResource(context, R.array.fanboys_social_blocking_list_array, R.layout.spinner_item)
312         val ultraListArrayAdapter = ArrayAdapter.createFromResource(context, R.array.ultralist_array, R.layout.spinner_item)
313         val ultraPrivacyArrayAdapter = ArrayAdapter.createFromResource(context, R.array.ultraprivacy_array, R.layout.spinner_item)
314         val blockAllThirdPartyRequestsArrayAdapter = ArrayAdapter.createFromResource(context, R.array.block_all_third_party_requests_array, R.layout.spinner_item)
315         val fontSizeArrayAdapter = ArrayAdapter.createFromResource(context, R.array.font_size_array, R.layout.spinner_item)
316         val swipeToRefreshArrayAdapter = ArrayAdapter.createFromResource(context, R.array.swipe_to_refresh_array, R.layout.spinner_item)
317         val webViewThemeArrayAdapter = ArrayAdapter.createFromResource(context, R.array.webview_theme_array, R.layout.spinner_item)
318         val wideViewportArrayAdapter = ArrayAdapter.createFromResource(context, R.array.wide_viewport_array, R.layout.spinner_item)
319         val displayImagesArrayAdapter = ArrayAdapter.createFromResource(context, R.array.display_webpage_images_array, R.layout.spinner_item)
320
321         // Set the drop down view resource on the spinners.
322         javaScriptArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items)
323         cookiesArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items)
324         domStorageArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items)
325         translatedUserAgentArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items)
326         easyListArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items)
327         easyPrivacyArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items)
328         fanboysAnnoyanceListArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items)
329         fanboysSocialBlockingListArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items)
330         ultraListArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items)
331         ultraPrivacyArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items)
332         blockAllThirdPartyRequestsArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items)
333         fontSizeArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items)
334         swipeToRefreshArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items)
335         webViewThemeArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items)
336         wideViewportArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items)
337         displayImagesArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items)
338
339         // Set the array adapters for the spinners.
340         javaScriptSpinner.adapter = javaScriptArrayAdapter
341         cookiesSpinner.adapter = cookiesArrayAdapter
342         domStorageSpinner.adapter = domStorageArrayAdapter
343         userAgentSpinner.adapter = translatedUserAgentArrayAdapter
344         easyListSpinner.adapter = easyListArrayAdapter
345         easyPrivacySpinner.adapter = easyPrivacyArrayAdapter
346         fanboysAnnoyanceListSpinner.adapter = fanboysAnnoyanceListArrayAdapter
347         fanboysSocialBlockingListSpinner.adapter = fanboysSocialBlockingListArrayAdapter
348         ultraListSpinner.adapter = ultraListArrayAdapter
349         ultraPrivacySpinner.adapter = ultraPrivacyArrayAdapter
350         blockAllThirdPartyRequestsSpinner.adapter = blockAllThirdPartyRequestsArrayAdapter
351         fontSizeSpinner.adapter = fontSizeArrayAdapter
352         swipeToRefreshSpinner.adapter = swipeToRefreshArrayAdapter
353         webViewThemeSpinner.adapter = webViewThemeArrayAdapter
354         wideViewportSpinner.adapter = wideViewportArrayAdapter
355         displayImagesSpinner.adapter = displayImagesArrayAdapter
356
357         // Open the spinners when the text view is tapped.
358         javaScriptTextView.setOnClickListener { javaScriptSpinner.performClick() }
359         cookiesTextView.setOnClickListener { cookiesSpinner.performClick() }
360         domStorageTextView.setOnClickListener { domStorageSpinner.performClick() }
361         userAgentTextView.setOnClickListener { userAgentSpinner.performClick() }
362         easyListTextView.setOnClickListener { easyListSpinner.performClick() }
363         easyPrivacyTextView.setOnClickListener { easyPrivacySpinner.performClick() }
364         fanboysAnnoyanceListTextView.setOnClickListener { fanboysAnnoyanceListSpinner.performClick() }
365         fanboysSocialBlockingListTextView.setOnClickListener { fanboysSocialBlockingListSpinner.performClick() }
366         ultraListTextView.setOnClickListener { ultraListSpinner.performClick() }
367         ultraPrivacyTextView.setOnClickListener { ultraPrivacySpinner.performClick() }
368         blockAllThirdPartyRequestsTextView.setOnClickListener { blockAllThirdPartyRequestsSpinner.performClick() }
369         defaultFontSizeTextView.setOnClickListener { fontSizeSpinner.performClick() }
370         swipeToRefreshTextView.setOnClickListener { swipeToRefreshSpinner.performClick() }
371         webViewThemeTextView.setOnClickListener { webViewThemeSpinner.performClick() }
372         wideViewportTextView.setOnClickListener { wideViewportSpinner.performClick() }
373         displayImagesTextView.setOnClickListener { displayImagesSpinner.performClick() }
374
375         // Set the spinner selections.  Items that aren't defined by an integer are handled individually below.
376         javaScriptSpinner.setSelection(javaScriptInt)
377         cookiesSpinner.setSelection(cookiesInt)
378         domStorageSpinner.setSelection(domStorageInt)
379         easyListSpinner.setSelection(easyListInt)
380         easyPrivacySpinner.setSelection(easyPrivacyInt)
381         fanboysAnnoyanceListSpinner.setSelection(fanboysAnnoyanceListInt)
382         fanboysSocialBlockingListSpinner.setSelection(fanboysSocialBlockingListInt)
383         ultraListSpinner.setSelection(ultraListInt)
384         ultraPrivacySpinner.setSelection(ultraPrivacyInt)
385         blockAllThirdPartyRequestsSpinner.setSelection(blockAllThirdPartyRequestsInt)
386         swipeToRefreshSpinner.setSelection(swipeToRefreshInt)
387         webViewThemeSpinner.setSelection(webViewThemeInt)
388         wideViewportSpinner.setSelection(wideViewportInt)
389         displayImagesSpinner.setSelection(displayImagesInt)
390
391         // Populate the text views.  Items that aren't defined by an integer are handled individually below.
392         populateTextView(javaScriptDefault, javaScriptArrayAdapter, javaScriptTextView)
393         populateTextView(cookiesDefault, cookiesArrayAdapter, cookiesTextView)
394         populateTextView(domStorageDefault, domStorageArrayAdapter, domStorageTextView)
395         populateTextView(easyListDefault, easyListArrayAdapter, easyListTextView)
396         populateTextView(easyPrivacyDefault, easyPrivacyArrayAdapter, easyPrivacyTextView)
397         populateTextView(fanboysAnnoyanceListDefault, fanboysAnnoyanceListArrayAdapter, fanboysAnnoyanceListTextView)
398         populateTextView(fanboysSocialBlockingListDefault, fanboysSocialBlockingListArrayAdapter, fanboysSocialBlockingListTextView)
399         populateTextView(ultraListDefault, ultraListArrayAdapter, ultraListTextView)
400         populateTextView(ultraPrivacyDefault, ultraPrivacyArrayAdapter, ultraPrivacyTextView)
401         populateTextView(blockAllThirdPartyRequestsDefault, blockAllThirdPartyRequestsArrayAdapter, blockAllThirdPartyRequestsTextView)
402         populateTextView(swipeToRefreshDefault, swipeToRefreshArrayAdapter, swipeToRefreshTextView)
403         populateTextView(wideViewportDefault, wideViewportArrayAdapter, wideViewportTextView)
404         populateTextView(displayWebpageImagesDefault, displayImagesArrayAdapter, displayImagesTextView)
405
406         // Set the icon and text view settings.  Non-standard items are handled individually below.
407         setIconAndTextViewSettings(cookiesInt, cookiesDefault, cookiesLinearLayout, cookiesImageView, cookiesTextView)
408         setIconAndTextViewSettings(domStorageInt, domStorageDefault, domStorageLinearLayout, domStorageImageView, domStorageTextView)
409         setIconAndTextViewSettings(easyListInt, easyListDefault, easyListLinearLayout, easyListImageView, easyListTextView)
410         setIconAndTextViewSettings(easyPrivacyInt, easyPrivacyDefault, easyPrivacyLinearLayout, easyPrivacyImageView, easyListTextView)
411         setIconAndTextViewSettings(fanboysAnnoyanceListInt, fanboysAnnoyanceListDefault, fanboysAnnoyanceListLinearLayout, fanboysAnnoyanceListImageView, fanboysAnnoyanceListTextView)
412         setIconAndTextViewSettings(fanboysSocialBlockingListInt, fanboysSocialBlockingListDefault, fanboysSocialBlockingListLinearLayout, fanboysSocialBlockingListImageView, fanboysSocialBlockingListTextView)
413         setIconAndTextViewSettings(ultraListInt, ultraListDefault, ultraListLinearLayout, ultraListImageView, ultraListTextView)
414         setIconAndTextViewSettings(ultraPrivacyInt, ultraPrivacyDefault, ultraPrivacyLinearLayout, ultraPrivacyImageView, ultraPrivacyTextView)
415         setIconAndTextViewSettings(blockAllThirdPartyRequestsInt, blockAllThirdPartyRequestsDefault, blockAllThirdPartyRequestsLinearLayout, blockAllThirdPartyRequestsImageView,
416             blockAllThirdPartyRequestsTextView)
417         setIconAndTextViewSettings(swipeToRefreshInt, swipeToRefreshDefault, swipeToRefreshLinearLayout, swipeToRefreshImageView, swipeToRefreshTextView)
418         setIconAndTextViewSettings(wideViewportInt, wideViewportDefault, wideViewportLinearLayout, wideViewportImageView, wideViewportTextView)
419         setIconAndTextViewSettings(displayImagesInt, displayWebpageImagesDefault, displayImagesLinearLayout, displayImagesImageView, displayImagesTextView)
420
421
422         // Set the domain name from the the database cursor.
423         domainNameEditText.setText(domainNameString)
424
425         // Setup the pinned labels.
426         val cNameLabel = getString(R.string.common_name)
427         val oNameLabel = getString(R.string.organization)
428         val uNameLabel = getString(R.string.organizational_unit)
429         val startDateLabel = getString(R.string.start_date)
430         val endDateLabel = getString(R.string.end_date)
431
432         // Create the color spans.
433         val blueColorSpan = ForegroundColorSpan(context.getColor(R.color.alt_blue_text))
434         val redColorSpan = ForegroundColorSpan(context.getColor(R.color.red_text))
435
436         // Update the certificates' Common Name color when the domain name text changes.
437         domainNameEditText.addTextChangedListener(object : TextWatcher {
438             override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
439                 // Do nothing.
440             }
441
442             override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
443                 // Do nothing.
444             }
445
446             override fun afterTextChanged(s: Editable) {
447                 // Get the new domain name.
448                 val newDomainName = domainNameEditText.text.toString()
449
450                 // Check the saved SSL certificate against the new domain name.
451                 val savedSslMatchesNewDomainName = checkDomainNameAgainstCertificate(newDomainName, savedSslIssuedToCNameString)
452
453                 // Create a spannable string builder for the saved certificate's Common Name.
454                 val savedSslCNameStringBuilder = SpannableStringBuilder(cNameLabel + savedSslIssuedToCNameString)
455
456                 // Format the saved certificate's Common Name color.  `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
457                 if (savedSslMatchesNewDomainName) {
458                     savedSslCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length, savedSslCNameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
459                 } else {
460                     savedSslCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length, savedSslCNameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
461                 }
462
463                 // Update the saved SSL issued to CName text view.
464                 savedSslIssuedToCNameTextView.text = savedSslCNameStringBuilder
465
466                 // Update the current website certificate if it exists.
467                 if (DomainsActivity.sslIssuedToCName != null) {
468                     // Check the current website certificate against the new domain name.
469                     val currentSslMatchesNewDomainName = checkDomainNameAgainstCertificate(newDomainName, DomainsActivity.sslIssuedToCName)
470
471                     // Create a spannable string builder for the current website certificate's Common Name.
472                     val currentSslCNameStringBuilder = SpannableStringBuilder(cNameLabel + DomainsActivity.sslIssuedToCName)
473
474                     // Format the current certificate Common Name color.  `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
475                     if (currentSslMatchesNewDomainName) {
476                         currentSslCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length, currentSslCNameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
477                     } else {
478                         currentSslCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length, currentSslCNameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
479                     }
480
481                     // Update the current SSL issued to CName text view.
482                     currentSslIssuedToCNameTextView.text = currentSslCNameStringBuilder
483                 }
484             }
485         })
486
487
488         // Set the javaScript icon and text view settings.
489         when (javaScriptInt) {
490             SYSTEM_DEFAULT -> {
491                 // Set the icon.
492                 if (javaScriptDefault)
493                     javaScriptImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.javascript_enabled, null))
494                 else
495                     javaScriptImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.privacy_mode, null))
496
497                 // Show the text view.
498                 javaScriptTextView.visibility = View.VISIBLE
499
500                 // Set the background color to be transparent.
501                 javaScriptLinearLayout.setBackgroundColor(getColor(context, R.color.transparent))
502             }
503
504             ENABLED -> {
505                 // Set the icon.
506                 javaScriptImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.javascript_enabled, null))
507
508                 // Hide the text view.
509                 javaScriptTextView.visibility = View.GONE
510
511                 // Set the background color to be blue.
512                 javaScriptLinearLayout.setBackgroundColor(getColor(context, R.color.blue_background))
513             }
514
515             DISABLED -> {
516                 // Set the icon.
517                 javaScriptImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.privacy_mode, null))
518
519                 // Hide the text view.
520                 javaScriptTextView.visibility = View.GONE
521
522                 // Set the background color to be blue.
523                 javaScriptLinearLayout.setBackgroundColor(getColor(context, R.color.blue_background))
524             }
525         }
526
527
528         // Calculate if JavaScript is enabled, either because it is the system default and that default is enabled, or because it is explicitly set to be enabled for this domain.
529         val javaScriptEnabled = (((javaScriptInt == 0) && javaScriptDefault) || (javaScriptInt == 1))
530
531         // Set the DOM storage spinner and text view status based on the JavaScript status.
532         domStorageSpinner.isEnabled = javaScriptEnabled
533         domStorageTextView.isEnabled = javaScriptEnabled
534
535         // Set the DOM storage icon ghosted status based on the JavaScript status.
536         domStorageImageView.isEnabled = javaScriptEnabled
537
538
539         // Inflated a WebView to get the default user agent.
540         // `@SuppressLint("InflateParams")` removes the warning about using `null` as the `ViewGroup`, which in this case makes sense because the bare WebView should not be displayed on the screen.
541         @SuppressLint("InflateParams") val bareWebViewLayout = inflater.inflate(R.layout.bare_webview, null, false)
542
543         // Get a handle for the bare WebView.
544         val bareWebView = bareWebViewLayout.findViewById<WebView>(R.id.bare_webview)
545
546         // Get the default user agent.
547         val webViewDefaultUserAgentString = bareWebView.settings.userAgentString
548
549         // Get a handle for the user agent array adapter.  This array does not contain the `System default` entry.
550         val userAgentNamesArray = ArrayAdapter.createFromResource(context, R.array.user_agent_names, R.layout.spinner_item)
551
552         // Get the positions of the user agent and the default user agent.
553         val userAgentArrayPosition = userAgentNamesArray.getPosition(currentUserAgentName)
554         val defaultUserAgentArrayPosition = userAgentNamesArray.getPosition(userAgentDefault)
555
556         // Get a handle for the user agent data array.  This array does not contain the `System default` entry.
557         val userAgentDataArray = resources.getStringArray(R.array.user_agent_data)
558
559         // Set the user agent text.
560         if (currentUserAgentName == getString(R.string.system_default_user_agent)) {  // Use the system default user agent.
561             // Set the user agent according to the system default.
562             when (defaultUserAgentArrayPosition) {
563                 // This is probably because it was set in an older version of Privacy Browser before the switch to persistent user agent names.
564                 UNRECOGNIZED_USER_AGENT -> userAgentTextView.text = userAgentDefault
565
566                 // Display the WebView default user agent.
567                 SETTINGS_WEBVIEW_DEFAULT_USER_AGENT -> userAgentTextView.text = webViewDefaultUserAgentString
568
569                 // Display the custom user agent.
570                 SETTINGS_CUSTOM_USER_AGENT -> userAgentTextView.text = customUserAgentStringDefault
571
572                 // Get the user agent string from the user agent data array.
573                 else -> userAgentTextView.text = userAgentDataArray[defaultUserAgentArrayPosition]
574             }
575
576             // Set the background color to be transparent.
577             userAgentLinearLayout.setBackgroundColor(getColor(context, R.color.transparent))
578         } else if (userAgentArrayPosition == UNRECOGNIZED_USER_AGENT || currentUserAgentName == getString(R.string.custom_user_agent)) {
579             // A custom user agent is stored in the current user agent name.  The second check is necessary in case the user did not change the default custom text.
580             // Set the user agent spinner to `Custom user agent`.
581             userAgentSpinner.setSelection(DOMAINS_CUSTOM_USER_AGENT)
582
583             // Hide the user agent text view.
584             userAgentTextView.visibility = View.GONE
585
586             // Show the custom user agent edit text and set the current user agent name as the text.
587             customUserAgentEditText.visibility = View.VISIBLE
588             customUserAgentEditText.setText(currentUserAgentName)
589
590             // Set the background color to be blue.
591             userAgentLinearLayout.setBackgroundColor(getColor(context, R.color.blue_background))
592         } else {  // The user agent name contains one of the canonical user agents.
593             // Set the user agent spinner selection.  The spinner has one more entry at the beginning than the user agent data array, so the position must be incremented.
594             userAgentSpinner.setSelection(userAgentArrayPosition + 1)
595
596             // Show the user agent text view.
597             userAgentTextView.visibility = View.VISIBLE
598
599             // Hide the custom user agent edit text.
600             customUserAgentEditText.visibility = View.GONE
601
602             // Set the user agent text.
603             if (userAgentArrayPosition == DOMAINS_WEBVIEW_DEFAULT_USER_AGENT) {  // The WebView default user agent is selected.
604                 // Display the WebView default user agent.
605                 userAgentTextView.text = webViewDefaultUserAgentString
606             } else {  // A user agent besides the default is selected.
607                 // Get the user agent string from the user agent data array.  The spinner has one more entry at the beginning than the user agent data array, so the position must be incremented.
608                 userAgentTextView.text = userAgentDataArray[userAgentArrayPosition + 1]
609             }
610
611             // Set the background color to be blue.
612             userAgentLinearLayout.setBackgroundColor(getColor(context, R.color.blue_background))
613         }
614
615
616         // Calculate if Fanboy's Annoyance List is enabled, either because it is the system default and that default is enabled, or because it is explicitly set to be enabled for this domain.
617         val fanboysAnnoyanceListEnabled = (((fanboysAnnoyanceListInt == 0) && fanboysAnnoyanceListDefault) || (fanboysAnnoyanceListInt == 1))
618
619         // Set Fanboy's Social Blocking List spinner and text view status based on the Annoyance List status.
620         fanboysSocialBlockingListSpinner.isEnabled = !fanboysAnnoyanceListEnabled
621         fanboysSocialBlockingListTextView.isEnabled = !fanboysAnnoyanceListEnabled
622
623         // Set the Social Blocking List icon ghosted status based on the Annoyance List status.
624         fanboysSocialBlockingListImageView.isEnabled = !fanboysAnnoyanceListEnabled
625
626
627         // Display the font size settings.
628         if (fontSizeInt == SYSTEM_DEFAULT) {  // `0` is the code for system default font size.
629             // Set the font size to the system default.
630             fontSizeSpinner.setSelection(SYSTEM_DEFAULT)
631
632             // Show the default font size text view.
633             defaultFontSizeTextView.visibility = View.VISIBLE
634
635             // Hide the custom font size edit text.
636             customFontSizeEditText.visibility = View.GONE
637
638             // Set the default font size as the text of the custom font size edit text.  This way, if the user switches to custom it will already be populated.
639             customFontSizeEditText.setText(fontSizeStringDefault)
640
641             // Set the background color to be transparent.
642             fontSizeLinearLayout.setBackgroundColor(getColor(context, R.color.transparent))
643         } else {  // A custom font size is selected.
644             // Set the spinner to the custom font size.
645             fontSizeSpinner.setSelection(1)
646
647             // Hide the default font size text view.
648             defaultFontSizeTextView.visibility = View.GONE
649
650             // Show the custom font size edit text.
651             customFontSizeEditText.visibility = View.GONE
652
653             // Set the custom font size.
654             customFontSizeEditText.setText(fontSizeInt.toString())
655
656             // Set the background color to be blue.
657             fontSizeLinearLayout.setBackgroundColor(getColor(context, R.color.blue_background))
658         }
659
660         // Initialize the default font size percentage string.
661         val defaultFontSizePercentageString = "$fontSizeStringDefault%"
662
663         // Set the default font size text in the text view.
664         defaultFontSizeTextView.text = defaultFontSizePercentageString
665
666
667         // Get the WebView theme string arrays.
668         val webViewThemeStringArray = resources.getStringArray(R.array.webview_theme_array)
669         val webViewThemeEntryValuesStringArray = resources.getStringArray(R.array.webview_theme_entry_values)
670
671         // Get the WebView theme entry number that matches the current WebView theme string.
672         val appWebViewThemeEntryNumber = when (webViewThemeDefault) {
673             webViewThemeEntryValuesStringArray[1] -> { LIGHT_THEME }  // The light theme is selected.
674             webViewThemeEntryValuesStringArray[2] -> { DARK_THEME }  // The dark theme is selected.
675             else -> { SYSTEM_DEFAULT }  // The system default theme is selected.
676         }
677
678         // Set the WebView theme text.  This is only displayed if system default is selection, but it should be set here in case the user changes the selection.
679         if (appWebViewThemeEntryNumber == SYSTEM_DEFAULT) {  // The app WebView theme is system default.
680             // Set the text according to the current UI theme.
681             if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO)
682                 webViewThemeTextView.text = webViewThemeStringArray[LIGHT_THEME]
683             else
684                 webViewThemeTextView.text = webViewThemeStringArray[DARK_THEME]
685         } else {  // The app WebView theme is not system default.
686             // Set the text according to the app WebView theme.
687             webViewThemeTextView.text = webViewThemeStringArray[appWebViewThemeEntryNumber]
688         }
689
690         // Set the WebView theme icon and text visibility.
691         when (webViewThemeInt) {
692             SYSTEM_DEFAULT -> {
693                 // Set the icon color.
694                 when (appWebViewThemeEntryNumber) {
695                     SYSTEM_DEFAULT -> webViewThemeImageView.isSelected = (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO)
696                     LIGHT_THEME -> webViewThemeImageView.isSelected = true
697                     DARK_THEME -> webViewThemeImageView.isSelected = false
698                 }
699
700                 // Show the WebView theme text view.
701                 webViewThemeTextView.visibility = View.VISIBLE
702
703                 // Set the background color to be transparent.
704                 webViewThemeLinearLayout.setBackgroundColor(getColor(context, R.color.transparent))
705             }
706
707             LIGHT_THEME -> {
708                 // Set the icon color.
709                 webViewThemeImageView.isSelected = true
710
711                 // Hide the WebView theme text view.
712                 webViewThemeTextView.visibility = View.GONE
713
714                 // Set the background color to be blue.
715                 webViewThemeLinearLayout.setBackgroundColor(getColor(context, R.color.blue_background))
716             }
717
718             DARK_THEME -> {
719                 // Set the icon color.
720                 webViewThemeImageView.isSelected = false
721
722                 // Hide the WebView theme text view.
723                 webViewThemeTextView.visibility = View.GONE
724
725                 // Set the background color to be blue.
726                 webViewThemeLinearLayout.setBackgroundColor(getColor(context, R.color.blue_background))
727             }
728         }
729
730
731         // Set the switch positions.
732         pinnedSslCertificateSwitch.isChecked = (pinnedSslCertificateInt == 1)
733         pinnedIpAddressesSwitch.isChecked = (pinnedIpAddressesInt == 1)
734
735         // Set the switch icon colors.
736         pinnedSslCertificateImageView.isSelected = (pinnedSslCertificateInt == 1)
737         pinnedIpAddressesImageView.isSelected = (pinnedIpAddressesInt == 1)
738
739         // Store the current date.
740         val currentDate = Calendar.getInstance().time
741
742         // Create a spannable string builder for each text view that needs multiple colors of text.
743         val savedSslIssuedToCNameStringBuilder = SpannableStringBuilder(cNameLabel + savedSslIssuedToCNameString)
744         val savedSslIssuedToONameStringBuilder = SpannableStringBuilder(oNameLabel + savedSslIssuedToONameString)
745         val savedSslIssuedToUNameStringBuilder = SpannableStringBuilder(uNameLabel + savedSslIssuedToUNameString)
746         val savedSslIssuedByCNameStringBuilder = SpannableStringBuilder(cNameLabel + savedSslIssuedByCNameString)
747         val savedSslIssuedByONameStringBuilder = SpannableStringBuilder(oNameLabel + savedSslIssuedByONameString)
748         val savedSslIssuedByUNameStringBuilder = SpannableStringBuilder(uNameLabel + savedSslIssuedByUNameString)
749
750         // Initialize the saved SSL certificate date variables.
751         var savedSslStartDate: Date? = null
752         var savedSslEndDate: Date? = null
753
754         // Only get the saved SSL certificate dates from the cursor if they are not set to `0`.
755         if (savedSslStartDateLong != 0L)
756             savedSslStartDate = Date(savedSslStartDateLong)
757         if (savedSslEndDateLong != 0L)
758             savedSslEndDate = Date(savedSslEndDateLong)
759
760         // Create the date spannable string builders.
761         val savedSslStartDateStringBuilder: SpannableStringBuilder = if (savedSslStartDate == null)
762             SpannableStringBuilder(startDateLabel)
763         else
764             SpannableStringBuilder(startDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(savedSslStartDate))
765
766         val savedSslEndDateStringBuilder: SpannableStringBuilder = if (savedSslEndDate == null)
767             SpannableStringBuilder(endDateLabel)
768         else
769             SpannableStringBuilder(endDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(savedSslEndDate))
770
771         // Setup the string builders to display the general certificate information in blue.  `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
772         savedSslIssuedToONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length, savedSslIssuedToONameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
773         savedSslIssuedToUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length, savedSslIssuedToUNameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
774         savedSslIssuedByCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length, savedSslIssuedByCNameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
775         savedSslIssuedByONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length, savedSslIssuedByONameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
776         savedSslIssuedByUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length, savedSslIssuedByUNameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
777
778         // Check the certificate Common Name against the domain name.
779         val savedSslCommonNameMatchesDomainName = checkDomainNameAgainstCertificate(domainNameString, savedSslIssuedToCNameString)
780
781         // Format the issued to Common Name color.  `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
782         if (savedSslCommonNameMatchesDomainName)
783             savedSslIssuedToCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length, savedSslIssuedToCNameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
784         else
785             savedSslIssuedToCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length, savedSslIssuedToCNameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
786
787         //  Format the start date color.  `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
788         if (savedSslStartDate != null && savedSslStartDate.after(currentDate))  // The certificate start date is in the future.
789             savedSslStartDateStringBuilder.setSpan(redColorSpan, startDateLabel.length, savedSslStartDateStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
790         else  // The certificate start date is in the past.
791             savedSslStartDateStringBuilder.setSpan(blueColorSpan, startDateLabel.length, savedSslStartDateStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
792
793         // Format the end date color.  `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
794         if (savedSslEndDate != null && savedSslEndDate.before(currentDate))  // The certificate end date is in the past.
795             savedSslEndDateStringBuilder.setSpan(redColorSpan, endDateLabel.length, savedSslEndDateStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
796         else  // The certificate end date is in the future.
797             savedSslEndDateStringBuilder.setSpan(blueColorSpan, endDateLabel.length, savedSslEndDateStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
798
799         // Display the saved website SSL certificate strings.
800         savedSslIssuedToCNameTextView.text = savedSslIssuedToCNameStringBuilder
801         savedSslIssuedToONameTextView.text = savedSslIssuedToONameStringBuilder
802         savedSslIssuedToUNameTextView.text = savedSslIssuedToUNameStringBuilder
803         savedSslIssuedByCNameTextView.text = savedSslIssuedByCNameStringBuilder
804         savedSslIssuedByONameTextView.text = savedSslIssuedByONameStringBuilder
805         savedSslIssuedByUNameTextView.text = savedSslIssuedByUNameStringBuilder
806         savedSslStartDateTextView.text = savedSslStartDateStringBuilder
807         savedSslEndDateTextView.text = savedSslEndDateStringBuilder
808
809         // Populate the current website SSL certificate if there is one.
810         if (DomainsActivity.sslIssuedToCName != null) {
811             // Get dates from the raw long values.
812             val currentSslStartDate = Date(DomainsActivity.sslStartDateLong)
813             val currentSslEndDate = Date(DomainsActivity.sslEndDateLong)
814
815             // Create a spannable string builder for each text view that needs multiple colors of text.
816             val currentSslIssuedToCNameStringBuilder = SpannableStringBuilder(cNameLabel + DomainsActivity.sslIssuedToCName)
817             val currentSslIssuedToONameStringBuilder = SpannableStringBuilder(oNameLabel + DomainsActivity.sslIssuedToOName)
818             val currentSslIssuedToUNameStringBuilder = SpannableStringBuilder(uNameLabel + DomainsActivity.sslIssuedToUName)
819             val currentSslIssuedByCNameStringBuilder = SpannableStringBuilder(cNameLabel + DomainsActivity.sslIssuedByCName)
820             val currentSslIssuedByONameStringBuilder = SpannableStringBuilder(oNameLabel + DomainsActivity.sslIssuedByOName)
821             val currentSslIssuedByUNameStringBuilder = SpannableStringBuilder(uNameLabel + DomainsActivity.sslIssuedByUName)
822             val currentSslStartDateStringBuilder = SpannableStringBuilder(startDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(currentSslStartDate))
823             val currentSslEndDateStringBuilder = SpannableStringBuilder(endDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(currentSslEndDate))
824
825             // Setup the string builders to display the general certificate information in blue.  `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
826             currentSslIssuedToONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length, currentSslIssuedToONameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
827             currentSslIssuedToUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length, currentSslIssuedToUNameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
828             currentSslIssuedByCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length, currentSslIssuedByCNameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
829             currentSslIssuedByONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length, currentSslIssuedByONameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
830             currentSslIssuedByUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length, currentSslIssuedByUNameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
831
832             // Check the certificate Common Name against the domain name.
833             val currentSslCommonNameMatchesDomainName = checkDomainNameAgainstCertificate(domainNameString, DomainsActivity.sslIssuedToCName)
834
835             // Format the issued to Common Name color.  `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
836             if (currentSslCommonNameMatchesDomainName)
837                 currentSslIssuedToCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length, currentSslIssuedToCNameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
838             else
839                 currentSslIssuedToCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length, currentSslIssuedToCNameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
840
841             //  Format the start date color.  `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
842             if (currentSslStartDate.after(currentDate))  // The certificate start date is in the future.
843                 currentSslStartDateStringBuilder.setSpan(redColorSpan, startDateLabel.length, currentSslStartDateStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
844             else  // The certificate start date is in the past.
845                 currentSslStartDateStringBuilder.setSpan(blueColorSpan, startDateLabel.length, currentSslStartDateStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
846
847             // Format the end date color.  `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
848             if (currentSslEndDate.before(currentDate))  // The certificate end date is in the past.
849                 currentSslEndDateStringBuilder.setSpan(redColorSpan, endDateLabel.length, currentSslEndDateStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
850             else  // The certificate end date is in the future.
851                 currentSslEndDateStringBuilder.setSpan(blueColorSpan, endDateLabel.length, currentSslEndDateStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
852
853             // Display the current website SSL certificate strings.
854             currentSslIssuedToCNameTextView.text = currentSslIssuedToCNameStringBuilder
855             currentSslIssuedToONameTextView.text = currentSslIssuedToONameStringBuilder
856             currentSslIssuedToUNameTextView.text = currentSslIssuedToUNameStringBuilder
857             currentSslIssuedByCNameTextView.text = currentSslIssuedByCNameStringBuilder
858             currentSslIssuedByONameTextView.text = currentSslIssuedByONameStringBuilder
859             currentSslIssuedByUNameTextView.text = currentSslIssuedByUNameStringBuilder
860             currentSslStartDateTextView.text = currentSslStartDateStringBuilder
861             currentSslEndDateTextView.text = currentSslEndDateStringBuilder
862         }
863
864         // Set the initial display status of the SSL certificates card views.
865         if (pinnedSslCertificateSwitch.isChecked) {  // An SSL certificate is pinned.
866             // Set the visibility of the saved SSL certificate.
867             if (savedSslIssuedToCNameString == null)
868                 savedSslCardView.visibility = View.GONE
869             else
870                 savedSslCardView.visibility = View.VISIBLE
871
872             // Set the visibility of the current website SSL certificate.
873             if (DomainsActivity.sslIssuedToCName == null) {  // There is no current SSL certificate.
874                 // Hide the SSL certificate.
875                 currentSslCardView.visibility = View.GONE
876
877                 // Show the instruction.
878                 noCurrentWebsiteCertificateTextView.visibility = View.VISIBLE
879             } else {  // There is a current SSL certificate.
880                 // Show the SSL certificate.
881                 currentSslCardView.visibility = View.VISIBLE
882
883                 // Hide the instruction.
884                 noCurrentWebsiteCertificateTextView.visibility = View.GONE
885             }
886
887             // Set the status of the radio buttons and the card view backgrounds.
888             if (savedSslCardView.visibility == View.VISIBLE) {  // The saved SSL certificate is displayed.
889                 // Check the saved SSL certificate radio button.
890                 savedSslCertificateRadioButton.isChecked = true
891
892                 // Uncheck the current website SSL certificate radio button.
893                 currentWebsiteCertificateRadioButton.isChecked = false
894
895                 // Darken the background of the current website SSL certificate linear layout.
896                 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.translucent_background)
897             } else if (currentSslCardView.visibility == View.VISIBLE) {  // The saved SSL certificate is hidden but the current website SSL certificate is visible.
898                 // Check the current website SSL certificate radio button.
899                 currentWebsiteCertificateRadioButton.isChecked = true
900
901                 // Uncheck the saved SSL certificate radio button.
902                 savedSslCertificateRadioButton.isChecked = false
903             } else {  // Neither SSL certificate is visible.
904                 // Uncheck both radio buttons.
905                 savedSslCertificateRadioButton.isChecked = false
906                 currentWebsiteCertificateRadioButton.isChecked = false
907             }
908         } else {  // An SSL certificate is not pinned.
909             // Hide the SSl certificates and instructions.
910             savedSslCardView.visibility = View.GONE
911             currentSslCardView.visibility = View.GONE
912             noCurrentWebsiteCertificateTextView.visibility = View.GONE
913
914             // Uncheck the radio buttons.
915             savedSslCertificateRadioButton.isChecked = false
916             currentWebsiteCertificateRadioButton.isChecked = false
917         }
918
919         // Populate the saved and current IP addresses.
920         savedIpAddressesTextView.text = savedIpAddresses
921         currentIpAddressesTextView.text = DomainsActivity.currentIpAddresses
922
923         // Set the initial display status of the IP addresses card views.
924         if (pinnedIpAddressesSwitch.isChecked) {  // IP addresses are pinned.
925             // Set the visibility of the saved IP addresses.
926             if (savedIpAddresses == null)  // There are no saved IP addresses.
927                 savedIpAddressesCardView.visibility = View.GONE
928             else  // There are saved IP addresses.
929                 savedIpAddressesCardView.visibility = View.VISIBLE
930
931             // Set the visibility of the current IP addresses.
932             currentIpAddressesCardView.visibility = View.VISIBLE
933
934             // Set the status of the radio buttons and the card view backgrounds.
935             if (savedIpAddressesCardView.visibility == View.VISIBLE) {  // The saved IP addresses are displayed.
936                 // Check the saved IP addresses radio button.
937                 savedIpAddressesRadioButton.isChecked = true
938
939                 // Uncheck the current IP addresses radio button.
940                 currentIpAddressesRadioButton.isChecked = false
941
942                 // Darken the background of the current IP addresses linear layout.
943                 currentIpAddressesLinearLayout.setBackgroundResource(R.color.translucent_background)
944             } else {  // The saved IP addresses are hidden.
945                 // Check the current IP addresses radio button.
946                 currentIpAddressesRadioButton.isChecked = true
947
948                 // Uncheck the saved IP addresses radio button.
949                 savedIpAddressesRadioButton.isChecked = false
950             }
951         } else {  // IP addresses are not pinned.
952             // Hide the IP addresses card views.
953             savedIpAddressesCardView.visibility = View.GONE
954             currentIpAddressesCardView.visibility = View.GONE
955
956             // Uncheck the radio buttons.
957             savedIpAddressesRadioButton.isChecked = false
958             currentIpAddressesRadioButton.isChecked = false
959         }
960
961
962         // Set the JavaScript spinner listener.
963         javaScriptSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
964             override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
965                 when (position) {
966                     SYSTEM_DEFAULT -> {
967                         // Set the icon.
968                         if (javaScriptDefault)
969                             javaScriptImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.javascript_enabled, null))
970                         else
971                             javaScriptImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.privacy_mode, null))
972
973                         // Show the text view.
974                         javaScriptTextView.visibility = View.VISIBLE
975
976                         // Set the background color to be transparent.
977                         javaScriptLinearLayout.setBackgroundColor(getColor(context, R.color.transparent))
978                     }
979
980                     ENABLED -> {
981                         // Set the icon.
982                         javaScriptImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.javascript_enabled, null))
983
984                         // Hide the text view.
985                         javaScriptTextView.visibility = View.GONE
986
987                         // Set the background color to be blue.
988                         javaScriptLinearLayout.setBackgroundColor(getColor(context, R.color.blue_background))
989                     }
990
991                     DISABLED -> {
992                         // Set the icon.
993                         javaScriptImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.privacy_mode, null))
994
995                         // Hide the text view.
996                         javaScriptTextView.visibility = View.GONE
997
998                         // Set the background color to be blue.
999                         javaScriptLinearLayout.setBackgroundColor(getColor(context, R.color.blue_background))
1000                     }
1001                 }
1002
1003                 // Calculate if JavaScript is enabled, either because it is the system default and that default is enabled, or because it is explicitly set to be enabled for this domain.
1004                 val updatedJavaScriptEnabled = (((position == 0) && javaScriptDefault) || (position == 1))
1005
1006                 // Set the DOM storage spinner and text view status based on the JavaScript status.
1007                 domStorageSpinner.isEnabled = updatedJavaScriptEnabled
1008                 domStorageTextView.isEnabled = updatedJavaScriptEnabled
1009
1010                 // Set the DOM storage icon ghosted status based on the JavaScript status.
1011                 domStorageImageView.isEnabled = updatedJavaScriptEnabled
1012             }
1013
1014             override fun onNothingSelected(parent: AdapterView<*>?) {
1015                 // Do nothing.
1016             }
1017         }
1018
1019         // Set the cookies switch listener.
1020         cookiesSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
1021             override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
1022                 // Update the icon and the text view settings.
1023                 setIconAndTextViewSettings(position, cookiesDefault, cookiesLinearLayout, cookiesImageView, cookiesTextView)
1024             }
1025
1026             override fun onNothingSelected(parent: AdapterView<*>?) {
1027                 // Do nothing.
1028             }
1029         }
1030
1031         // Set the DOM Storage spinner listener.
1032         domStorageSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
1033             override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
1034                 // Update the icon and the text view settings.
1035                 setIconAndTextViewSettings(position, domStorageDefault, domStorageLinearLayout, domStorageImageView, domStorageTextView)
1036             }
1037
1038             override fun onNothingSelected(parent: AdapterView<*>?) {
1039                 // Do nothing.
1040             }
1041         }
1042
1043         // Set the user agent spinner listener.
1044         userAgentSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
1045             override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
1046                 // Set the new user agent.
1047                 when (position) {
1048                     DOMAINS_SYSTEM_DEFAULT_USER_AGENT -> {
1049                         // Show the user agent text view.
1050                         userAgentTextView.visibility = View.VISIBLE
1051
1052                         // Hide the custom user agent edit text.
1053                         customUserAgentEditText.visibility = View.GONE
1054
1055                         // Set the user text.
1056                         when (defaultUserAgentArrayPosition) {
1057                             // This is probably because it was set in an older version of Privacy Browser before the switch to persistent user agent names.
1058                             UNRECOGNIZED_USER_AGENT -> userAgentTextView.text = userAgentDefault
1059
1060                             // Display the `WebView` default user agent.
1061                             SETTINGS_WEBVIEW_DEFAULT_USER_AGENT -> userAgentTextView.text = webViewDefaultUserAgentString
1062
1063                             // Display the custom user agent.
1064                             SETTINGS_CUSTOM_USER_AGENT -> userAgentTextView.text = customUserAgentStringDefault
1065
1066                             // Get the user agent string from the user agent data array.
1067                             else -> userAgentTextView.text = userAgentDataArray[defaultUserAgentArrayPosition]
1068                         }
1069
1070                         // Set the background color to be transparent.
1071                         userAgentLinearLayout.setBackgroundColor(getColor(context, R.color.transparent))
1072                     }
1073
1074                     DOMAINS_WEBVIEW_DEFAULT_USER_AGENT -> {
1075                         // Show the user agent text view.
1076                         userAgentTextView.visibility = View.VISIBLE
1077
1078                         // Set the user agent text.
1079                         userAgentTextView.text = webViewDefaultUserAgentString
1080
1081                         // Hide the custom user agent edit text.
1082                         customUserAgentEditText.visibility = View.GONE
1083
1084                         // Set the background color to be blue.
1085                         userAgentLinearLayout.setBackgroundColor(getColor(context, R.color.blue_background))
1086                     }
1087
1088                     DOMAINS_CUSTOM_USER_AGENT -> {
1089                         // Hide the user agent text view.
1090                         userAgentTextView.visibility = View.GONE
1091
1092                         // Show the custom user agent edit text.
1093                         customUserAgentEditText.visibility = View.VISIBLE
1094
1095                         // Set the current user agent name as the text.
1096                         customUserAgentEditText.setText(currentUserAgentName)
1097
1098                         // Set the background color to be blue.
1099                         userAgentLinearLayout.setBackgroundColor(getColor(context, R.color.blue_background))
1100                     }
1101
1102                     else -> {
1103                         // Show the user agent text view.
1104                         userAgentTextView.visibility = View.VISIBLE
1105
1106                         // Set the text from the user agent data array, which has one less entry than the spinner, so the position must be decremented.
1107                         userAgentTextView.text = userAgentDataArray[position - 1]
1108
1109                         // Hide the custom user agent edit text.
1110                         customUserAgentEditText.visibility = View.GONE
1111
1112                         // Set the background color to be blue.
1113                         userAgentLinearLayout.setBackgroundColor(getColor(context, R.color.blue_background))
1114                     }
1115                 }
1116             }
1117
1118             override fun onNothingSelected(parent: AdapterView<*>?) {
1119                 // Do nothing.
1120             }
1121         }
1122
1123         // Set the EasyList spinner listener.
1124         easyListSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
1125             override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
1126                 // Update the icon and the text view settings.
1127                 setIconAndTextViewSettings(position, easyListDefault, easyListLinearLayout, easyListImageView, easyListTextView)
1128             }
1129
1130             override fun onNothingSelected(parent: AdapterView<*>?) {
1131                 // Do nothing.
1132             }
1133         }
1134
1135         // Set the EasyPrivacy spinner listener.
1136         easyPrivacySpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
1137             override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
1138                 // Update the icon and the text view settings.
1139                 setIconAndTextViewSettings(position, easyPrivacyDefault, easyPrivacyLinearLayout, easyPrivacyImageView, easyPrivacyTextView)
1140             }
1141
1142             override fun onNothingSelected(parent: AdapterView<*>?) {
1143                 // Do nothing.
1144             }
1145         }
1146
1147         // Set the Fanboy's Annoyance List spinner listener.
1148         fanboysAnnoyanceListSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
1149             override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
1150                 // Update the icon and the text view settings.
1151                 setIconAndTextViewSettings(position, fanboysAnnoyanceListDefault, fanboysAnnoyanceListLinearLayout, fanboysAnnoyanceListImageView, fanboysAnnoyanceListTextView)
1152
1153                 // Calculate if Fanboy's Annoyance List is enabled, either because it is the system default and that default is enabled, or because it is explicitly set to be enabled for this domain.
1154                 val updatedFanboysAnnoyanceListEnabled = (((position == 0) && fanboysAnnoyanceListDefault) || (position == 1))
1155
1156                 // Set Fanboy's Social Blocking List spinner and test view status based on the Annoyance List status.
1157                 fanboysSocialBlockingListSpinner.isEnabled = !updatedFanboysAnnoyanceListEnabled
1158                 fanboysSocialBlockingListTextView.isEnabled = !updatedFanboysAnnoyanceListEnabled
1159
1160                 // Set the Social Blocking List icon ghosted status based on the Annoyance List status.
1161                 fanboysSocialBlockingListImageView.isEnabled = !updatedFanboysAnnoyanceListEnabled
1162             }
1163
1164             override fun onNothingSelected(parent: AdapterView<*>?) {
1165                 // Do nothing.
1166             }
1167         }
1168
1169         // Set the Fanboy's Social Blocking List spinner listener.
1170         fanboysSocialBlockingListSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
1171             override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
1172                 // Update the icon and the text view settings.
1173                 setIconAndTextViewSettings(position, fanboysSocialBlockingListDefault, fanboysSocialBlockingListLinearLayout, fanboysSocialBlockingListImageView, fanboysSocialBlockingListTextView)
1174             }
1175
1176             override fun onNothingSelected(parent: AdapterView<*>?) {
1177                 // Do nothing.
1178             }
1179         }
1180
1181         // Set the UltraList spinner listener.
1182         ultraListSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
1183             override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
1184                 // Update the icon and the text view settings.
1185                 setIconAndTextViewSettings(position, ultraListDefault, ultraListLinearLayout, ultraListImageView, ultraListTextView)
1186             }
1187
1188             override fun onNothingSelected(parent: AdapterView<*>?) {
1189                 // Do nothing.
1190             }
1191         }
1192
1193         // Set the UltraPrivacy spinner listener.
1194         ultraPrivacySpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
1195             override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
1196                 // Update the icon and the text view settings.
1197                 setIconAndTextViewSettings(position, ultraPrivacyDefault, ultraPrivacyLinearLayout, ultraPrivacyImageView, ultraPrivacyTextView)
1198             }
1199
1200             override fun onNothingSelected(parent: AdapterView<*>?) {
1201                 // Do nothing.
1202             }
1203         }
1204
1205         // Set the block all third-party requests spinner listener.
1206         blockAllThirdPartyRequestsSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
1207             override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
1208                 // Update the icon and the text view settings.
1209                 setIconAndTextViewSettings(position, blockAllThirdPartyRequestsDefault, blockAllThirdPartyRequestsLinearLayout, blockAllThirdPartyRequestsImageView, blockAllThirdPartyRequestsTextView)
1210             }
1211
1212             override fun onNothingSelected(parent: AdapterView<*>?) {
1213                 // Do nothing.
1214             }
1215         }
1216
1217         // Set the font size spinner listener.
1218         fontSizeSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
1219             override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
1220                 // Update the font size display options.
1221                 if (position == SYSTEM_DEFAULT) {  // The system default font size has been selected.
1222                     // Show the default font size text view.
1223                     defaultFontSizeTextView.visibility = View.VISIBLE
1224
1225                     // Hide the custom font size edit text.
1226                     customFontSizeEditText.visibility = View.GONE
1227
1228                     // Set the background color to be transparent.
1229                     fontSizeLinearLayout.setBackgroundColor(getColor(context, R.color.transparent))
1230                 } else {  // A custom font size has been selected.
1231                     // Hide the default font size text view.
1232                     defaultFontSizeTextView.visibility = View.GONE
1233
1234                     // Show the custom font size edit text.
1235                     customFontSizeEditText.visibility = View.VISIBLE
1236
1237                     // Set the background color to be blue.
1238                     fontSizeLinearLayout.setBackgroundColor(getColor(context, R.color.blue_background))
1239                 }
1240             }
1241
1242             override fun onNothingSelected(parent: AdapterView<*>?) {
1243                 // Do nothing.
1244             }
1245         }
1246
1247         // Set the swipe-to-refresh spinner listener.
1248         swipeToRefreshSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
1249             override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
1250                 // Update the icon and the text view settings.
1251                 setIconAndTextViewSettings(position, swipeToRefreshDefault, swipeToRefreshLinearLayout, swipeToRefreshImageView, swipeToRefreshTextView)
1252             }
1253
1254             override fun onNothingSelected(parent: AdapterView<*>?) {
1255                 // Do nothing.
1256             }
1257         }
1258
1259         // Set the WebView theme spinner listener.
1260         webViewThemeSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
1261             override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
1262                 // Update the icon and the WebView theme text view settings.
1263                 when (position) {
1264                     SYSTEM_DEFAULT -> {
1265                         // Set the icon color.
1266                         when (appWebViewThemeEntryNumber) {
1267                             SYSTEM_DEFAULT -> webViewThemeImageView.isSelected = (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO)
1268                             LIGHT_THEME -> webViewThemeImageView.isSelected = true
1269                             DARK_THEME -> webViewThemeImageView.isSelected = false
1270                         }
1271
1272                         // Show the WebView theme text view.
1273                         webViewThemeTextView.visibility = View.VISIBLE
1274
1275                         // Set the background color to be transparent.
1276                         webViewThemeLinearLayout.setBackgroundColor(getColor(context, R.color.transparent))
1277                     }
1278
1279                     LIGHT_THEME -> {
1280                         // Set the icon color.
1281                         webViewThemeImageView.isSelected = true
1282
1283                         // Hide the WebView theme text view.
1284                         webViewThemeTextView.visibility = View.GONE
1285
1286                         // Set the background color to be blue.
1287                         webViewThemeLinearLayout.setBackgroundColor(getColor(context, R.color.blue_background))
1288                     }
1289
1290                     DARK_THEME -> {
1291                         // Set the icon color.
1292                         webViewThemeImageView.isSelected = false
1293
1294                         // Hide the WebView theme text view.
1295                         webViewThemeTextView.visibility = View.GONE
1296
1297                         // Set the background color to be blue.
1298                         webViewThemeLinearLayout.setBackgroundColor(getColor(context, R.color.blue_background))
1299                     }
1300                 }
1301             }
1302
1303             override fun onNothingSelected(parent: AdapterView<*>?) {
1304                 // Do nothing.
1305             }
1306         }
1307
1308         // Set the wide viewport spinner listener.
1309         wideViewportSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
1310             override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
1311                 // Update the icon and the text view settings.
1312                 setIconAndTextViewSettings(position, wideViewportDefault, wideViewportLinearLayout, wideViewportImageView, wideViewportTextView)
1313             }
1314
1315             override fun onNothingSelected(parent: AdapterView<*>?) {
1316                 // Do nothing.
1317             }
1318         }
1319
1320         // Set the display webpage images spinner listener.
1321         displayImagesSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
1322             override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
1323                 // Update the icon and the text view settings.
1324                 setIconAndTextViewSettings(position, displayWebpageImagesDefault, displayImagesLinearLayout, displayImagesImageView, displayImagesTextView)
1325             }
1326
1327             override fun onNothingSelected(parent: AdapterView<*>?) {
1328                 // Do nothing.
1329             }
1330         }
1331
1332         // Set the pinned SSL certificate switch listener.
1333         pinnedSslCertificateSwitch.setOnCheckedChangeListener { _: CompoundButton?, isChecked: Boolean ->
1334             // Update the icon color.
1335             pinnedSslCertificateImageView.isSelected = isChecked
1336
1337             // Update the views.
1338             if (isChecked) {  // SSL certificate pinning is enabled.
1339                 // Update the visibility of the saved SSL certificate.
1340                 if (savedSslIssuedToCNameString == null)
1341                     savedSslCardView.visibility = View.GONE
1342                 else
1343                     savedSslCardView.visibility = View.VISIBLE
1344
1345                 // Update the visibility of the current website SSL certificate.
1346                 if (DomainsActivity.sslIssuedToCName == null) {
1347                     // Hide the SSL certificate.
1348                     currentSslCardView.visibility = View.GONE
1349
1350                     // Show the instruction.
1351                     noCurrentWebsiteCertificateTextView.visibility = View.VISIBLE
1352                 } else {
1353                     // Show the SSL certificate.
1354                     currentSslCardView.visibility = View.VISIBLE
1355
1356                     // Hide the instruction.
1357                     noCurrentWebsiteCertificateTextView.visibility = View.GONE
1358                 }
1359
1360                 // Set the status of the radio buttons.
1361                 if (savedSslCardView.visibility == View.VISIBLE) {  // The saved SSL certificate is displayed.
1362                     // Check the saved SSL certificate radio button.
1363                     savedSslCertificateRadioButton.isChecked = true
1364
1365                     // Uncheck the current website SSL certificate radio button.
1366                     currentWebsiteCertificateRadioButton.isChecked = false
1367
1368                     // Set the background of the saved SSL certificate linear layout to be transparent.
1369                     savedSslCertificateLinearLayout.setBackgroundResource(R.color.transparent)
1370
1371                     // Darken the background of the current website SSL certificate linear layout according to the theme.
1372                     currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.translucent_background)
1373
1374                     // Scroll to the current website SSL certificate card.
1375                     savedSslCardView.parent.requestChildFocus(savedSslCardView, savedSslCardView)
1376                 } else if (currentSslCardView.visibility == View.VISIBLE) {  // The saved SSL certificate is hidden but the current website SSL certificate is visible.
1377                     // Check the current website SSL certificate radio button.
1378                     currentWebsiteCertificateRadioButton.isChecked = true
1379
1380                     // Uncheck the saved SSL certificate radio button.
1381                     savedSslCertificateRadioButton.isChecked = false
1382
1383                     // Set the background of the current website SSL certificate linear layout to be transparent.
1384                     currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.transparent)
1385
1386                     // Darken the background of the saved SSL certificate linear layout according to the theme.
1387                     savedSslCertificateLinearLayout.setBackgroundResource(R.color.translucent_background)
1388
1389                     // Scroll to the current website SSL certificate card.
1390                     currentSslCardView.parent.requestChildFocus(currentSslCardView, currentSslCardView)
1391                 } else {  // Neither SSL certificate is visible.
1392                     // Uncheck both radio buttons.
1393                     savedSslCertificateRadioButton.isChecked = false
1394                     currentWebsiteCertificateRadioButton.isChecked = false
1395
1396                     // Scroll to the current website SSL certificate card.
1397                     noCurrentWebsiteCertificateTextView.parent.requestChildFocus(noCurrentWebsiteCertificateTextView, noCurrentWebsiteCertificateTextView)
1398                 }
1399             } else {  // SSL certificate pinning is disabled.
1400                 // Hide the SSl certificates and instructions.
1401                 savedSslCardView.visibility = View.GONE
1402                 currentSslCardView.visibility = View.GONE
1403                 noCurrentWebsiteCertificateTextView.visibility = View.GONE
1404
1405                 // Uncheck the radio buttons.
1406                 savedSslCertificateRadioButton.isChecked = false
1407                 currentWebsiteCertificateRadioButton.isChecked = false
1408             }
1409         }
1410
1411         // Set the saved SSL card view listener.
1412         savedSslCardView.setOnClickListener {
1413             // Check the saved SSL certificate radio button.
1414             savedSslCertificateRadioButton.isChecked = true
1415
1416             // Uncheck the current website SSL certificate radio button.
1417             currentWebsiteCertificateRadioButton.isChecked = false
1418
1419             // Set the background of the saved SSL certificate linear layout to be transparent.
1420             savedSslCertificateLinearLayout.setBackgroundResource(R.color.transparent)
1421
1422             // Darken the background of the current website SSL certificate linear layout.
1423             currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.translucent_background)
1424         }
1425
1426         // Set the saved SSL certificate radio button listener.
1427         savedSslCertificateRadioButton.setOnClickListener {
1428             // Check the saved SSL certificate radio button.
1429             savedSslCertificateRadioButton.isChecked = true
1430
1431             // Uncheck the current website SSL certificate radio button.
1432             currentWebsiteCertificateRadioButton.isChecked = false
1433
1434             // Set the background of the saved SSL certificate linear layout to be transparent.
1435             savedSslCertificateLinearLayout.setBackgroundResource(R.color.transparent)
1436
1437             // Darken the background of the current website SSL certificate linear layout.
1438             currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.translucent_background)
1439         }
1440
1441         // Set the current SSL card view listener.
1442         currentSslCardView.setOnClickListener {
1443             // Check the current website SSL certificate radio button.
1444             currentWebsiteCertificateRadioButton.isChecked = true
1445
1446             // Uncheck the saved SSL certificate radio button.
1447             savedSslCertificateRadioButton.isChecked = false
1448
1449             // Set the background of the current website SSL certificate linear layout to be transparent.
1450             currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.transparent)
1451
1452             // Darken the background of the saved SSL certificate linear layout.
1453             savedSslCertificateLinearLayout.setBackgroundResource(R.color.translucent_background)
1454         }
1455
1456         // Set the current website certificate radio button listener.
1457         currentWebsiteCertificateRadioButton.setOnClickListener {
1458             // Check the current website SSL certificate radio button.
1459             currentWebsiteCertificateRadioButton.isChecked = true
1460
1461             // Uncheck the saved SSL certificate radio button.
1462             savedSslCertificateRadioButton.isChecked = false
1463
1464             // Set the background of the current website SSL certificate linear layout to be transparent.
1465             currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.transparent)
1466
1467             // Darken the background of the saved SSL certificate linear layout.
1468             savedSslCertificateLinearLayout.setBackgroundResource(R.color.translucent_background)
1469         }
1470
1471         // Set the pinned IP addresses switch listener.
1472         pinnedIpAddressesSwitch.setOnCheckedChangeListener { _: CompoundButton?, isChecked: Boolean ->
1473             // Update the icon color.
1474             pinnedIpAddressesImageView.isSelected = isChecked
1475
1476             // Update the views.
1477             if (isChecked) {  // IP addresses pinning is enabled.
1478                 // Update the visibility of the saved IP addresses card view.
1479                 if (savedIpAddresses == null)
1480                     savedIpAddressesCardView.visibility = View.GONE
1481                 else
1482                     savedIpAddressesCardView.visibility = View.VISIBLE
1483
1484                 // Show the current IP addresses card view.
1485                 currentIpAddressesCardView.visibility = View.VISIBLE
1486
1487                 // Set the status of the radio buttons.
1488                 if (savedIpAddressesCardView.visibility == View.VISIBLE) {  // The saved IP addresses are visible.
1489                     // Check the saved IP addresses radio button.
1490                     savedIpAddressesRadioButton.isChecked = true
1491
1492                     // Uncheck the current IP addresses radio button.
1493                     currentIpAddressesRadioButton.isChecked = false
1494
1495                     // Set the background of the saved IP addresses linear layout to be transparent.
1496                     savedSslCertificateLinearLayout.setBackgroundResource(R.color.transparent)
1497
1498                     // Darken the background of the current IP addresses linear layout.
1499                     currentIpAddressesLinearLayout.setBackgroundResource(R.color.translucent_background)
1500                 } else {  // The saved IP addresses are not visible.
1501                     // Check the current IP addresses radio button.
1502                     currentIpAddressesRadioButton.isChecked = true
1503
1504                     // Uncheck the saved IP addresses radio button.
1505                     savedIpAddressesRadioButton.isChecked = false
1506
1507                     // Set the background of the current IP addresses linear layout to be transparent.
1508                     currentIpAddressesLinearLayout.setBackgroundResource(R.color.transparent)
1509
1510                     // Darken the background of the saved IP addresses linear layout.
1511                     savedIpAddressesLinearLayout.setBackgroundResource(R.color.translucent_background)
1512                 }
1513
1514                 // Scroll to the bottom of the card views.
1515                 currentIpAddressesCardView.parent.requestChildFocus(currentIpAddressesCardView, currentIpAddressesCardView)
1516             } else {  // IP addresses pinning is disabled.
1517                 // Hide the IP addresses card views.
1518                 savedIpAddressesCardView.visibility = View.GONE
1519                 currentIpAddressesCardView.visibility = View.GONE
1520
1521                 // Uncheck the radio buttons.
1522                 savedIpAddressesRadioButton.isChecked = false
1523                 currentIpAddressesRadioButton.isChecked = false
1524             }
1525         }
1526
1527         // Set the saved IP addresses card view listener.
1528         savedIpAddressesCardView.setOnClickListener {
1529             // Check the saved IP addresses radio button.
1530             savedIpAddressesRadioButton.isChecked = true
1531
1532             // Uncheck the current website IP addresses radio button.
1533             currentIpAddressesRadioButton.isChecked = false
1534
1535             // Set the background of the saved IP addresses linear layout to be transparent.
1536             savedIpAddressesLinearLayout.setBackgroundResource(R.color.transparent)
1537
1538             // Darken the background of the current IP addresses linear layout.
1539                 currentIpAddressesLinearLayout.setBackgroundResource(R.color.translucent_background)
1540         }
1541
1542         // Set the saved IP addresses radio button listener.
1543         savedIpAddressesRadioButton.setOnClickListener {
1544             // Check the saved IP addresses radio button.
1545             savedIpAddressesRadioButton.isChecked = true
1546
1547             // Uncheck the current website IP addresses radio button.
1548             currentIpAddressesRadioButton.isChecked = false
1549
1550             // Set the background of the saved IP addresses linear layout to be transparent.
1551             savedIpAddressesLinearLayout.setBackgroundResource(R.color.transparent)
1552
1553             // Darken the background of the current IP addresses linear layout.
1554             currentIpAddressesLinearLayout.setBackgroundResource(R.color.translucent_background)
1555         }
1556
1557         // Set the current IP addresses card view listener.
1558         currentIpAddressesCardView.setOnClickListener {
1559             // Check the current IP addresses radio button.
1560             currentIpAddressesRadioButton.isChecked = true
1561
1562             // Uncheck the saved IP addresses radio button.
1563             savedIpAddressesRadioButton.isChecked = false
1564
1565             // Set the background of the current IP addresses linear layout to be transparent.
1566             currentIpAddressesLinearLayout.setBackgroundResource(R.color.transparent)
1567
1568             // Darken the background of the saved IP addresses linear layout.
1569             savedIpAddressesLinearLayout.setBackgroundResource(R.color.translucent_background)
1570         }
1571
1572         // Set the current IP addresses radio button listener.
1573         currentIpAddressesRadioButton.setOnClickListener {
1574             // Check the current IP addresses radio button.
1575             currentIpAddressesRadioButton.isChecked = true
1576
1577             // Uncheck the saved IP addresses radio button.
1578             savedIpAddressesRadioButton.isChecked = false
1579
1580             // Set the background of the current IP addresses linear layout to be transparent.
1581             currentIpAddressesLinearLayout.setBackgroundResource(R.color.transparent)
1582
1583             // Darken the background of the saved IP addresses linear layout.
1584             savedIpAddressesLinearLayout.setBackgroundResource(R.color.translucent_background)
1585         }
1586
1587         // Set the scroll Y.
1588         domainSettingsScrollView.post { domainSettingsScrollView.scrollY = scrollY }
1589
1590         // Return the domain settings view.
1591         return domainSettingsView
1592     }
1593
1594     private fun checkDomainNameAgainstCertificate(domainName: String?, certificateCommonName: String?): Boolean {
1595         // Initialize the domain names match tracker.
1596         var domainNamesMatch = false
1597
1598         // Check various wildcard permutations if the domain name and the certificate Common Name are not empty.
1599         if ((domainName != null) && (certificateCommonName != null)) {
1600             // Check if the domains match.
1601             if (domainName == certificateCommonName)
1602                 domainNamesMatch = true
1603
1604             // If the domain name starts with a wildcard, check the base domain against all the subdomains of the certificate Common Name.
1605             if (!domainNamesMatch && domainName.startsWith("*.") && domainName.length > 2) {
1606                 // Remove the initial `*.`.
1607                 val baseDomainName = domainName.substring(2)
1608
1609                 // Create a copy of the certificate Common Name to test subdomains.
1610                 var certificateCommonNameSubdomain: String = certificateCommonName
1611
1612                 // Check all the subdomains in the certificate Common Name subdomain against the base domain name.
1613                 while (!domainNamesMatch && certificateCommonNameSubdomain.contains(".")) {  // Stop checking if the domain names match or if there are no more dots.
1614                     // Test the certificate Common Name subdomain against the base domain name.
1615                     if (certificateCommonNameSubdomain == baseDomainName)
1616                         domainNamesMatch = true
1617
1618                     // Strip out the lowest subdomain of the certificate Common Name subdomain.
1619                     certificateCommonNameSubdomain = try {
1620                         certificateCommonNameSubdomain.substring(certificateCommonNameSubdomain.indexOf(".") + 1)
1621                     } catch (e: IndexOutOfBoundsException) {  // The certificate Common Name subdomain ends with a dot.
1622                         ""
1623                     }
1624                 }
1625             }
1626
1627             // If the certificate Common Name starts with a wildcard, check the base common name against all the subdomains of the domain name.
1628             if (!domainNamesMatch && certificateCommonName.startsWith("*.") && certificateCommonName.length > 2) {
1629                 // Remove the initial `*.`.
1630                 val baseCertificateCommonName = certificateCommonName.substring(2)
1631
1632                 // Setup a copy of domain name to test subdomains.
1633                 var domainNameSubdomain: String = domainName
1634
1635                 // Check all the subdomains in the domain name subdomain against the base certificate Common Name.
1636                 while (!domainNamesMatch && domainNameSubdomain.contains(".") && domainNameSubdomain.length > 2) {
1637                     // Test the domain name subdomain  against the base certificate Common Name.
1638                     if (domainNameSubdomain == baseCertificateCommonName)
1639                         domainNamesMatch = true
1640
1641                     // Strip out the lowest subdomain of the domain name subdomain.
1642                     domainNameSubdomain = try {
1643                         domainNameSubdomain.substring(domainNameSubdomain.indexOf(".") + 1)
1644                     } catch (e: IndexOutOfBoundsException) {  // `domainNameSubdomain` ends with a dot.
1645                         ""
1646                     }
1647                 }
1648             }
1649
1650             // If both names start with a wildcard, check if the root of one contains the root of the other.
1651             if (!domainNamesMatch && domainName.startsWith("*.") && domainName.length > 2 && certificateCommonName.startsWith("*.") && certificateCommonName.length > 2) {
1652                 // Remove the wildcards.
1653                 val rootDomainName = domainName.substring(2)
1654                 val rootCertificateCommonName = certificateCommonName.substring(2)
1655
1656                 // Check if one name ends with the contents of the other.  If so, there will be overlap in the their wildcard subdomains.
1657                 if (rootDomainName.endsWith(rootCertificateCommonName) || rootCertificateCommonName.endsWith(rootDomainName))
1658                     domainNamesMatch = true
1659             }
1660         }
1661
1662         return domainNamesMatch
1663     }
1664
1665     private fun populateTextView(defaultValue: Boolean, arrayAdapter: ArrayAdapter<CharSequence>, textView: TextView) {
1666         // Set the text.
1667         textView.text = if (defaultValue)
1668             arrayAdapter.getItem(ENABLED)
1669         else
1670             arrayAdapter.getItem(DISABLED)
1671     }
1672
1673     private fun setIconAndTextViewSettings(databaseInt: Int, defaultValue: Boolean, linearLayout: LinearLayout, imageView: ImageView, textView: TextView) {
1674         // Set the icon and text view settings.
1675         when (databaseInt) {
1676             SYSTEM_DEFAULT -> {
1677                 // Set the icon color.
1678                 imageView.isSelected = defaultValue
1679
1680                 // Show the text view.
1681                 textView.visibility = View.VISIBLE
1682
1683                 // Set the background color to be transparent.
1684                 linearLayout.setBackgroundColor(getColor(context, R.color.transparent))
1685             }
1686
1687             ENABLED -> {
1688                 // Set the icon color.
1689                 imageView.isSelected = true
1690
1691                 // Hide the text view.
1692                 textView.visibility = View.GONE
1693
1694                 // Set the background color to be blue.
1695                 linearLayout.setBackgroundColor(getColor(context, R.color.blue_background))
1696             }
1697
1698             DISABLED -> {
1699                 // Set the icon color.
1700                 imageView.isSelected = false
1701
1702                 // Hide the text view.
1703                 textView.visibility = View.GONE
1704
1705                 // Set the background color to be blue.
1706                 linearLayout.setBackgroundColor(getColor(context, R.color.blue_background))
1707             }
1708         }
1709     }
1710 }