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