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