2 * Copyright 2017-2023 Soren Stoutner <soren@stoutner.com>.
4 * This file is part of Privacy Browser Android <https://www.stoutner.com/privacy-browser-android>.
6 * Privacy Browser Android is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * Privacy Browser Android is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with Privacy Browser Android. If not, see <http://www.gnu.org/licenses/>.
20 package com.stoutner.privacybrowser.fragments
22 import android.annotation.SuppressLint
23 import android.content.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
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
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
98 import java.lang.IndexOutOfBoundsException
99 import java.text.DateFormat
100 import java.util.Calendar
101 import java.util.Date
103 class DomainSettingsFragment : Fragment() {
104 // Define the class variables.
105 private var scrollY = 0
107 // Declare the class variables.
108 private lateinit var context: Context
111 // Define the public constants.
112 const val DATABASE_ID = "database_id"
113 const val SCROLL_Y = "scroll_y"
115 // Define the public variables. `databaseId` is public so it can be accessed from `DomainsActivity`.
119 override fun onCreate(savedInstanceState: Bundle?) {
120 // Run the default commands.
121 super.onCreate(savedInstanceState)
123 // Store the arguments in class variables.
124 databaseId = requireArguments().getInt(DATABASE_ID)
125 scrollY = requireArguments().getInt(SCROLL_Y)
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)
132 // Get a handle for the context.
133 context = requireContext()
135 // Get the current theme status.
136 val currentThemeStatus = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
138 // Get a handle for the shared preference.
139 val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
141 // Get the default values.
142 val javaScriptDefault = sharedPreferences.getBoolean(getString(R.string.javascript_key), false)
143 val cookiesDefault = sharedPreferences.getBoolean(getString(R.string.cookies_key), false)
144 val domStorageDefault = sharedPreferences.getBoolean(getString(R.string.dom_storage_key), false)
145 val formDataDefault = sharedPreferences.getBoolean(getString(R.string.save_form_data_key), false) // The form data views can be remove once the minimum API >= 26.
146 val easyListDefault = sharedPreferences.getBoolean(getString(R.string.easylist_key), true)
147 val easyPrivacyDefault = sharedPreferences.getBoolean(getString(R.string.easyprivacy_key), true)
148 val fanboysAnnoyanceListDefault = sharedPreferences.getBoolean(getString(R.string.fanboys_annoyance_list_key), true)
149 val fanboysSocialBlockingListDefault = sharedPreferences.getBoolean(getString(R.string.fanboys_social_blocking_list), true)
150 val ultraListDefault = sharedPreferences.getBoolean(getString(R.string.ultralist_key), true)
151 val ultraPrivacyDefault = sharedPreferences.getBoolean(getString(R.string.ultraprivacy_key), true)
152 val blockAllThirdPartyRequestsDefault = sharedPreferences.getBoolean(getString(R.string.block_all_third_party_requests_key), false)
153 val userAgentDefault = sharedPreferences.getString(getString(R.string.user_agent_key), getString(R.string.user_agent_default_value))
154 val customUserAgentStringDefault = sharedPreferences.getString(getString(R.string.custom_user_agent_key), getString(R.string.custom_user_agent_default_value))
155 val fontSizeStringDefault = sharedPreferences.getString(getString(R.string.font_size_key), getString(R.string.font_size_default_value))
156 val swipeToRefreshDefault = sharedPreferences.getBoolean(getString(R.string.swipe_to_refresh_key), true)
157 val webViewThemeDefault = sharedPreferences.getString(getString(R.string.webview_theme_key), getString(R.string.webview_theme_default_value))
158 val wideViewportDefault = sharedPreferences.getBoolean(getString(R.string.wide_viewport_key), true)
159 val displayWebpageImagesDefault = sharedPreferences.getBoolean(getString(R.string.display_webpage_images_key), true)
161 // Get handles for the views.
162 val domainSettingsScrollView = domainSettingsView.findViewById<ScrollView>(R.id.domain_settings_scrollview)
163 val domainNameEditText = domainSettingsView.findViewById<EditText>(R.id.domain_settings_name_edittext)
164 val javaScriptLinearLayout = domainSettingsView.findViewById<LinearLayout>(R.id.javascript_linearlayout)
165 val javaScriptImageView = domainSettingsView.findViewById<ImageView>(R.id.javascript_imageview)
166 val javaScriptSpinner = domainSettingsView.findViewById<Spinner>(R.id.javascript_spinner)
167 val javaScriptTextView = domainSettingsView.findViewById<TextView>(R.id.javascript_textview)
168 val cookiesLinearLayout = domainSettingsView.findViewById<LinearLayout>(R.id.cookies_linearlayout)
169 val cookiesImageView = domainSettingsView.findViewById<ImageView>(R.id.cookies_imageview)
170 val cookiesSpinner = domainSettingsView.findViewById<Spinner>(R.id.cookies_spinner)
171 val cookiesTextView = domainSettingsView.findViewById<TextView>(R.id.cookies_textview)
172 val domStorageLinearLayout = domainSettingsView.findViewById<LinearLayout>(R.id.dom_storage_linearlayout)
173 val domStorageImageView = domainSettingsView.findViewById<ImageView>(R.id.dom_storage_imageview)
174 val domStorageSpinner = domainSettingsView.findViewById<Spinner>(R.id.dom_storage_spinner)
175 val domStorageTextView = domainSettingsView.findViewById<TextView>(R.id.dom_storage_textview)
176 val formDataLinearLayout = domainSettingsView.findViewById<LinearLayout>(R.id.form_data_linearlayout) // The form data views can be remove once the minimum API >= 26.
177 val formDataImageView = domainSettingsView.findViewById<ImageView>(R.id.form_data_imageview) // The form data views can be remove once the minimum API >= 26.
178 val formDataSpinner = domainSettingsView.findViewById<Spinner>(R.id.form_data_spinner) // The form data views can be remove once the minimum API >= 26.
179 val formDataTextView = domainSettingsView.findViewById<TextView>(R.id.form_data_textview) // The form data views can be remove once the minimum API >= 26.
180 val easyListLinearLayout = domainSettingsView.findViewById<LinearLayout>(R.id.easylist_linearlayout)
181 val easyListImageView = domainSettingsView.findViewById<ImageView>(R.id.easylist_imageview)
182 val easyListSpinner = domainSettingsView.findViewById<Spinner>(R.id.easylist_spinner)
183 val easyListTextView = domainSettingsView.findViewById<TextView>(R.id.easylist_textview)
184 val easyPrivacyLinearLayout = domainSettingsView.findViewById<LinearLayout>(R.id.easyprivacy_linearlayout)
185 val easyPrivacyImageView = domainSettingsView.findViewById<ImageView>(R.id.easyprivacy_imageview)
186 val easyPrivacySpinner = domainSettingsView.findViewById<Spinner>(R.id.easyprivacy_spinner)
187 val easyPrivacyTextView = domainSettingsView.findViewById<TextView>(R.id.easyprivacy_textview)
188 val fanboysAnnoyanceListLinearLayout = domainSettingsView.findViewById<LinearLayout>(R.id.fanboys_annoyance_list_linearlayout)
189 val fanboysAnnoyanceListImageView = domainSettingsView.findViewById<ImageView>(R.id.fanboys_annoyance_list_imageview)
190 val fanboysAnnoyanceListSpinner = domainSettingsView.findViewById<Spinner>(R.id.fanboys_annoyance_list_spinner)
191 val fanboysAnnoyanceListTextView = domainSettingsView.findViewById<TextView>(R.id.fanboys_annoyance_list_textview)
192 val fanboysSocialBlockingListLinearLayout = domainSettingsView.findViewById<LinearLayout>(R.id.fanboys_social_blocking_list_linearlayout)
193 val fanboysSocialBlockingListImageView = domainSettingsView.findViewById<ImageView>(R.id.fanboys_social_blocking_list_imageview)
194 val fanboysSocialBlockingListSpinner = domainSettingsView.findViewById<Spinner>(R.id.fanboys_social_blocking_list_spinner)
195 val fanboysSocialBlockingListTextView = domainSettingsView.findViewById<TextView>(R.id.fanboys_social_blocking_list_textview)
196 val ultraListLinearLayout = domainSettingsView.findViewById<LinearLayout>(R.id.ultralist_linearlayout)
197 val ultraListImageView = domainSettingsView.findViewById<ImageView>(R.id.ultralist_imageview)
198 val ultraListSpinner = domainSettingsView.findViewById<Spinner>(R.id.ultralist_spinner)
199 val ultraListTextView = domainSettingsView.findViewById<TextView>(R.id.ultralist_textview)
200 val ultraPrivacyLinearLayout = domainSettingsView.findViewById<LinearLayout>(R.id.ultraprivacy_linearlayout)
201 val ultraPrivacyImageView = domainSettingsView.findViewById<ImageView>(R.id.ultraprivacy_imageview)
202 val ultraPrivacySpinner = domainSettingsView.findViewById<Spinner>(R.id.ultraprivacy_spinner)
203 val ultraPrivacyTextView = domainSettingsView.findViewById<TextView>(R.id.ultraprivacy_textview)
204 val blockAllThirdPartyRequestsLinearLayout = domainSettingsView.findViewById<LinearLayout>(R.id.block_all_third_party_requests_linearlayout)
205 val blockAllThirdPartyRequestsImageView = domainSettingsView.findViewById<ImageView>(R.id.block_all_third_party_requests_imageview)
206 val blockAllThirdPartyRequestsSpinner = domainSettingsView.findViewById<Spinner>(R.id.block_all_third_party_requests_spinner)
207 val blockAllThirdPartyRequestsTextView = domainSettingsView.findViewById<TextView>(R.id.block_all_third_party_requests_textview)
208 val userAgentLinearLayout = domainSettingsView.findViewById<LinearLayout>(R.id.user_agent_linearlayout)
209 val userAgentSpinner = domainSettingsView.findViewById<Spinner>(R.id.user_agent_spinner)
210 val userAgentTextView = domainSettingsView.findViewById<TextView>(R.id.user_agent_textview)
211 val customUserAgentEditText = domainSettingsView.findViewById<EditText>(R.id.custom_user_agent_edittext)
212 val fontSizeLinearLayout = domainSettingsView.findViewById<LinearLayout>(R.id.font_size_linearlayout)
213 val fontSizeSpinner = domainSettingsView.findViewById<Spinner>(R.id.font_size_spinner)
214 val defaultFontSizeTextView = domainSettingsView.findViewById<TextView>(R.id.default_font_size_textview)
215 val customFontSizeEditText = domainSettingsView.findViewById<EditText>(R.id.custom_font_size_edittext)
216 val swipeToRefreshLinearLayout = domainSettingsView.findViewById<LinearLayout>(R.id.swipe_to_refresh_linearlayout)
217 val swipeToRefreshImageView = domainSettingsView.findViewById<ImageView>(R.id.swipe_to_refresh_imageview)
218 val swipeToRefreshSpinner = domainSettingsView.findViewById<Spinner>(R.id.swipe_to_refresh_spinner)
219 val swipeToRefreshTextView = domainSettingsView.findViewById<TextView>(R.id.swipe_to_refresh_textview)
220 val webViewThemeLinearLayout = domainSettingsView.findViewById<LinearLayout>(R.id.webview_theme_linearlayout)
221 val webViewThemeImageView = domainSettingsView.findViewById<ImageView>(R.id.webview_theme_imageview)
222 val webViewThemeSpinner = domainSettingsView.findViewById<Spinner>(R.id.webview_theme_spinner)
223 val webViewThemeTextView = domainSettingsView.findViewById<TextView>(R.id.webview_theme_textview)
224 val wideViewportLinearLayout = domainSettingsView.findViewById<LinearLayout>(R.id.wide_viewport_linearlayout)
225 val wideViewportImageView = domainSettingsView.findViewById<ImageView>(R.id.wide_viewport_imageview)
226 val wideViewportSpinner = domainSettingsView.findViewById<Spinner>(R.id.wide_viewport_spinner)
227 val wideViewportTextView = domainSettingsView.findViewById<TextView>(R.id.wide_viewport_textview)
228 val displayImagesLinearLayout = domainSettingsView.findViewById<LinearLayout>(R.id.display_images_linearlayout)
229 val displayImagesImageView = domainSettingsView.findViewById<ImageView>(R.id.display_images_imageview)
230 val displayImagesSpinner = domainSettingsView.findViewById<Spinner>(R.id.display_images_spinner)
231 val displayImagesTextView = domainSettingsView.findViewById<TextView>(R.id.display_images_textview)
232 val pinnedSslCertificateImageView = domainSettingsView.findViewById<ImageView>(R.id.pinned_ssl_certificate_imageview)
233 val pinnedSslCertificateSwitch = domainSettingsView.findViewById<SwitchCompat>(R.id.pinned_ssl_certificate_switch)
234 val savedSslCardView = domainSettingsView.findViewById<CardView>(R.id.saved_ssl_certificate_cardview)
235 val savedSslCertificateLinearLayout = domainSettingsView.findViewById<LinearLayout>(R.id.saved_ssl_certificate_linearlayout)
236 val savedSslCertificateRadioButton = domainSettingsView.findViewById<RadioButton>(R.id.saved_ssl_certificate_radiobutton)
237 val savedSslIssuedToCNameTextView = domainSettingsView.findViewById<TextView>(R.id.saved_ssl_certificate_issued_to_cname)
238 val savedSslIssuedToONameTextView = domainSettingsView.findViewById<TextView>(R.id.saved_ssl_certificate_issued_to_oname)
239 val savedSslIssuedToUNameTextView = domainSettingsView.findViewById<TextView>(R.id.saved_ssl_certificate_issued_to_uname)
240 val savedSslIssuedByCNameTextView = domainSettingsView.findViewById<TextView>(R.id.saved_ssl_certificate_issued_by_cname)
241 val savedSslIssuedByONameTextView = domainSettingsView.findViewById<TextView>(R.id.saved_ssl_certificate_issued_by_oname)
242 val savedSslIssuedByUNameTextView = domainSettingsView.findViewById<TextView>(R.id.saved_ssl_certificate_issued_by_uname)
243 val savedSslStartDateTextView = domainSettingsView.findViewById<TextView>(R.id.saved_ssl_certificate_start_date)
244 val savedSslEndDateTextView = domainSettingsView.findViewById<TextView>(R.id.saved_ssl_certificate_end_date)
245 val currentSslCardView = domainSettingsView.findViewById<CardView>(R.id.current_website_certificate_cardview)
246 val currentWebsiteCertificateLinearLayout = domainSettingsView.findViewById<LinearLayout>(R.id.current_website_certificate_linearlayout)
247 val currentWebsiteCertificateRadioButton = domainSettingsView.findViewById<RadioButton>(R.id.current_website_certificate_radiobutton)
248 val currentSslIssuedToCNameTextView = domainSettingsView.findViewById<TextView>(R.id.current_website_certificate_issued_to_cname)
249 val currentSslIssuedToONameTextView = domainSettingsView.findViewById<TextView>(R.id.current_website_certificate_issued_to_oname)
250 val currentSslIssuedToUNameTextView = domainSettingsView.findViewById<TextView>(R.id.current_website_certificate_issued_to_uname)
251 val currentSslIssuedByCNameTextView = domainSettingsView.findViewById<TextView>(R.id.current_website_certificate_issued_by_cname)
252 val currentSslIssuedByONameTextView = domainSettingsView.findViewById<TextView>(R.id.current_website_certificate_issued_by_oname)
253 val currentSslIssuedByUNameTextView = domainSettingsView.findViewById<TextView>(R.id.current_website_certificate_issued_by_uname)
254 val currentSslStartDateTextView = domainSettingsView.findViewById<TextView>(R.id.current_website_certificate_start_date)
255 val currentSslEndDateTextView = domainSettingsView.findViewById<TextView>(R.id.current_website_certificate_end_date)
256 val noCurrentWebsiteCertificateTextView = domainSettingsView.findViewById<TextView>(R.id.no_current_website_certificate)
257 val pinnedIpAddressesImageView = domainSettingsView.findViewById<ImageView>(R.id.pinned_ip_addresses_imageview)
258 val pinnedIpAddressesSwitch = domainSettingsView.findViewById<SwitchCompat>(R.id.pinned_ip_addresses_switch)
259 val savedIpAddressesCardView = domainSettingsView.findViewById<CardView>(R.id.saved_ip_addresses_cardview)
260 val savedIpAddressesLinearLayout = domainSettingsView.findViewById<LinearLayout>(R.id.saved_ip_addresses_linearlayout)
261 val savedIpAddressesRadioButton = domainSettingsView.findViewById<RadioButton>(R.id.saved_ip_addresses_radiobutton)
262 val savedIpAddressesTextView = domainSettingsView.findViewById<TextView>(R.id.saved_ip_addresses_textview)
263 val currentIpAddressesCardView = domainSettingsView.findViewById<CardView>(R.id.current_ip_addresses_cardview)
264 val currentIpAddressesLinearLayout = domainSettingsView.findViewById<LinearLayout>(R.id.current_ip_addresses_linearlayout)
265 val currentIpAddressesRadioButton = domainSettingsView.findViewById<RadioButton>(R.id.current_ip_addresses_radiobutton)
266 val currentIpAddressesTextView = domainSettingsView.findViewById<TextView>(R.id.current_ip_addresses_textview)
268 // Hide the form data linear layout if the API >= 26.
269 if (Build.VERSION.SDK_INT >= 26)
270 formDataLinearLayout.visibility = View.GONE
272 // Initialize the database handler.
273 val domainsDatabaseHelper = DomainsDatabaseHelper(requireContext())
275 // Get the database cursor for this ID.
276 val domainCursor = domainsDatabaseHelper.getCursorForId(databaseId)
278 // Move to the first row.
279 domainCursor.moveToFirst()
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 easyListInt = domainCursor.getInt(domainCursor.getColumnIndexOrThrow(ENABLE_EASYLIST))
288 val easyPrivacyInt = domainCursor.getInt(domainCursor.getColumnIndexOrThrow(ENABLE_EASYPRIVACY))
289 val fanboysAnnoyanceListInt = domainCursor.getInt(domainCursor.getColumnIndexOrThrow(ENABLE_FANBOYS_ANNOYANCE_LIST))
290 val fanboysSocialBlockingListInt = domainCursor.getInt(domainCursor.getColumnIndexOrThrow(ENABLE_FANBOYS_SOCIAL_BLOCKING_LIST))
291 val ultraListInt = domainCursor.getInt(domainCursor.getColumnIndexOrThrow(ULTRALIST))
292 val ultraPrivacyInt = domainCursor.getInt(domainCursor.getColumnIndexOrThrow(ENABLE_ULTRAPRIVACY))
293 val blockAllThirdPartyRequestsInt = domainCursor.getInt(domainCursor.getColumnIndexOrThrow(BLOCK_ALL_THIRD_PARTY_REQUESTS))
294 val currentUserAgentName = domainCursor.getString(domainCursor.getColumnIndexOrThrow(USER_AGENT))
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))
312 // Close the domain cursor.
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 easyListArrayAdapter = ArrayAdapter.createFromResource(context, R.array.easylist_array, R.layout.spinner_item)
321 val easyPrivacyArrayAdapter = ArrayAdapter.createFromResource(context, R.array.easyprivacy_array, R.layout.spinner_item)
322 val fanboysAnnoyanceListArrayAdapter = ArrayAdapter.createFromResource(context, R.array.fanboys_annoyance_list_array, R.layout.spinner_item)
323 val fanboysSocialBlockingListArrayAdapter = ArrayAdapter.createFromResource(context, R.array.fanboys_social_blocking_list_array, R.layout.spinner_item)
324 val ultraListArrayAdapter = ArrayAdapter.createFromResource(context, R.array.ultralist_array, R.layout.spinner_item)
325 val ultraPrivacyArrayAdapter = ArrayAdapter.createFromResource(context, R.array.ultraprivacy_array, R.layout.spinner_item)
326 val blockAllThirdPartyRequestsArrayAdapter = ArrayAdapter.createFromResource(context, R.array.block_all_third_party_requests_array, R.layout.spinner_item)
327 val translatedUserAgentArrayAdapter = ArrayAdapter.createFromResource(context, R.array.translated_domain_settings_user_agent_names, 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)
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 easyListArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items)
340 easyPrivacyArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items)
341 fanboysAnnoyanceListArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items)
342 fanboysSocialBlockingListArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items)
343 ultraListArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items)
344 ultraPrivacyArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items)
345 blockAllThirdPartyRequestsArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items)
346 translatedUserAgentArrayAdapter.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)
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 easyListSpinner.adapter = easyListArrayAdapter
359 easyPrivacySpinner.adapter = easyPrivacyArrayAdapter
360 fanboysAnnoyanceListSpinner.adapter = fanboysAnnoyanceListArrayAdapter
361 fanboysSocialBlockingListSpinner.adapter = fanboysSocialBlockingListArrayAdapter
362 ultraListSpinner.adapter = ultraListArrayAdapter
363 ultraPrivacySpinner.adapter = ultraPrivacyArrayAdapter
364 blockAllThirdPartyRequestsSpinner.adapter = blockAllThirdPartyRequestsArrayAdapter
365 userAgentSpinner.adapter = translatedUserAgentArrayAdapter
366 fontSizeSpinner.adapter = fontSizeArrayAdapter
367 swipeToRefreshSpinner.adapter = swipeToRefreshArrayAdapter
368 webViewThemeSpinner.adapter = webViewThemeArrayAdapter
369 wideViewportSpinner.adapter = wideViewportArrayAdapter
370 displayImagesSpinner.adapter = displayImagesArrayAdapter
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() }
377 easyListTextView.setOnClickListener { easyListSpinner.performClick() }
378 easyPrivacyTextView.setOnClickListener { easyPrivacySpinner.performClick() }
379 fanboysAnnoyanceListTextView.setOnClickListener { fanboysAnnoyanceListSpinner.performClick() }
380 fanboysSocialBlockingListTextView.setOnClickListener { fanboysSocialBlockingListSpinner.performClick() }
381 ultraListTextView.setOnClickListener { ultraListSpinner.performClick() }
382 ultraPrivacyTextView.setOnClickListener { ultraPrivacySpinner.performClick() }
383 blockAllThirdPartyRequestsTextView.setOnClickListener { blockAllThirdPartyRequestsSpinner.performClick() }
384 userAgentTextView.setOnClickListener { userAgentSpinner.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() }
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)
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)
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)
441 // Set the domain name from the the database cursor.
442 domainNameEditText.setText(domainNameString)
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)
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))
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) {
461 override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
465 override fun afterTextChanged(s: Editable) {
466 // Get the new domain name.
467 val newDomainName = domainNameEditText.text.toString()
469 // Check the saved SSL certificate against the new domain name.
470 val savedSslMatchesNewDomainName = checkDomainNameAgainstCertificate(newDomainName, savedSslIssuedToCNameString)
472 // Create a spannable string builder for the saved certificate's Common Name.
473 val savedSslCNameStringBuilder = SpannableStringBuilder(cNameLabel + savedSslIssuedToCNameString)
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)
479 savedSslCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length, savedSslCNameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
482 // Update the saved SSL issued to CName text view.
483 savedSslIssuedToCNameTextView.text = savedSslCNameStringBuilder
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)
490 // Create a spannable string builder for the current website certificate's Common Name.
491 val currentSslCNameStringBuilder = SpannableStringBuilder(cNameLabel + DomainsActivity.sslIssuedToCName)
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)
497 currentSslCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length, currentSslCNameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
500 // Update the current SSL issued to CName text view.
501 currentSslIssuedToCNameTextView.text = currentSslCNameStringBuilder
507 // Set the javaScript icon and text view settings.
508 when (javaScriptInt) {
511 if (javaScriptDefault)
512 javaScriptImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.javascript_enabled, null))
514 javaScriptImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.privacy_mode, null))
516 // Show the text view.
517 javaScriptTextView.visibility = View.VISIBLE
519 // Set the background color to be transparent.
520 javaScriptLinearLayout.setBackgroundColor(getColor(context, R.color.transparent))
525 javaScriptImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.javascript_enabled, null))
527 // Hide the text view.
528 javaScriptTextView.visibility = View.GONE
530 // Set the background color to be blue.
531 javaScriptLinearLayout.setBackgroundColor(getColor(context, R.color.blue_background))
536 javaScriptImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.privacy_mode, null))
538 // Hide the text view.
539 javaScriptTextView.visibility = View.GONE
541 // Set the background color to be blue.
542 javaScriptLinearLayout.setBackgroundColor(getColor(context, R.color.blue_background))
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))
550 // Set the DOM storage spinner and text view status based on the JavaScript status.
551 domStorageSpinner.isEnabled = javaScriptEnabled
552 domStorageTextView.isEnabled = javaScriptEnabled
554 // Set the DOM storage icon ghosted status based on the JavaScript status.
555 domStorageImageView.isEnabled = javaScriptEnabled
558 // 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.
559 val fanboysAnnoyanceListEnabled = (((fanboysAnnoyanceListInt == 0) && fanboysAnnoyanceListDefault) || (fanboysAnnoyanceListInt == 1))
561 // Set Fanboy's Social Blocking List spinner and text view status based on the Annoyance List status.
562 fanboysSocialBlockingListSpinner.isEnabled = !fanboysAnnoyanceListEnabled
563 fanboysSocialBlockingListTextView.isEnabled = !fanboysAnnoyanceListEnabled
565 // Set the Social Blocking List icon ghosted status based on the Annoyance List status.
566 fanboysSocialBlockingListImageView.isEnabled = !fanboysAnnoyanceListEnabled
569 // Inflated a WebView to get the default user agent.
570 // `@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.
571 @SuppressLint("InflateParams") val bareWebViewLayout = inflater.inflate(R.layout.bare_webview, null, false)
573 // Get a handle for the bare WebView.
574 val bareWebView = bareWebViewLayout.findViewById<WebView>(R.id.bare_webview)
576 // Get the default user agent.
577 val webViewDefaultUserAgentString = bareWebView.settings.userAgentString
579 // Get a handle for the user agent array adapter. This array does not contain the `System default` entry.
580 val userAgentNamesArray = ArrayAdapter.createFromResource(context, R.array.user_agent_names, R.layout.spinner_item)
582 // Get the positions of the user agent and the default user agent.
583 val userAgentArrayPosition = userAgentNamesArray.getPosition(currentUserAgentName)
584 val defaultUserAgentArrayPosition = userAgentNamesArray.getPosition(userAgentDefault)
586 // Get a handle for the user agent data array. This array does not contain the `System default` entry.
587 val userAgentDataArray = resources.getStringArray(R.array.user_agent_data)
589 // Set the user agent text.
590 if (currentUserAgentName == getString(R.string.system_default_user_agent)) { // Use the system default user agent.
591 // Set the user agent according to the system default.
592 when (defaultUserAgentArrayPosition) {
593 // This is probably because it was set in an older version of Privacy Browser before the switch to persistent user agent names.
594 UNRECOGNIZED_USER_AGENT -> userAgentTextView.text = userAgentDefault
596 // Display the WebView default user agent.
597 SETTINGS_WEBVIEW_DEFAULT_USER_AGENT -> userAgentTextView.text = webViewDefaultUserAgentString
599 // Display the custom user agent.
600 SETTINGS_CUSTOM_USER_AGENT -> userAgentTextView.text = customUserAgentStringDefault
602 // Get the user agent string from the user agent data array.
603 else -> userAgentTextView.text = userAgentDataArray[defaultUserAgentArrayPosition]
606 // Set the background color to be transparent.
607 userAgentLinearLayout.setBackgroundColor(getColor(context, R.color.transparent))
608 } else if (userAgentArrayPosition == UNRECOGNIZED_USER_AGENT || currentUserAgentName == getString(R.string.custom_user_agent)) {
609 // 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.
610 // Set the user agent spinner to `Custom user agent`.
611 userAgentSpinner.setSelection(DOMAINS_CUSTOM_USER_AGENT)
613 // Hide the user agent text view.
614 userAgentTextView.visibility = View.GONE
616 // Show the custom user agent edit text and set the current user agent name as the text.
617 customUserAgentEditText.visibility = View.VISIBLE
618 customUserAgentEditText.setText(currentUserAgentName)
620 // Set the background color to be blue.
621 userAgentLinearLayout.setBackgroundColor(getColor(context, R.color.blue_background))
622 } else { // The user agent name contains one of the canonical user agents.
623 // 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.
624 userAgentSpinner.setSelection(userAgentArrayPosition + 1)
626 // Show the user agent text view.
627 userAgentTextView.visibility = View.VISIBLE
629 // Hide the custom user agent edit text.
630 customUserAgentEditText.visibility = View.GONE
632 // Set the user agent text.
633 if (userAgentArrayPosition == DOMAINS_WEBVIEW_DEFAULT_USER_AGENT) { // The WebView default user agent is selected.
634 // Display the WebView default user agent.
635 userAgentTextView.text = webViewDefaultUserAgentString
636 } else { // A user agent besides the default is selected.
637 // 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.
638 userAgentTextView.text = userAgentDataArray[userAgentArrayPosition + 1]
641 // Set the background color to be blue.
642 userAgentLinearLayout.setBackgroundColor(getColor(context, R.color.blue_background))
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)
651 // Show the default font size text view.
652 defaultFontSizeTextView.visibility = View.VISIBLE
654 // Hide the custom font size edit text.
655 customFontSizeEditText.visibility = View.GONE
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)
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)
666 // Hide the default font size text view.
667 defaultFontSizeTextView.visibility = View.GONE
669 // Show the custom font size edit text.
670 customFontSizeEditText.visibility = View.GONE
672 // Set the custom font size.
673 customFontSizeEditText.setText(fontSizeInt.toString())
675 // Set the background color to be blue.
676 fontSizeLinearLayout.setBackgroundColor(getColor(context, R.color.blue_background))
679 // Initialize the default font size percentage string.
680 val defaultFontSizePercentageString = "$fontSizeStringDefault%"
682 // Set the default font size text in the text view.
683 defaultFontSizeTextView.text = defaultFontSizePercentageString
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)
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.
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]
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]
709 // Set the WebView theme icon and text visibility.
710 when (webViewThemeInt) {
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
719 // Show the WebView theme text view.
720 webViewThemeTextView.visibility = View.VISIBLE
722 // Set the background color to be transparent.
723 webViewThemeLinearLayout.setBackgroundColor(getColor(context, R.color.transparent))
727 // Set the icon color.
728 webViewThemeImageView.isSelected = true
730 // Hide the WebView theme text view.
731 webViewThemeTextView.visibility = View.GONE
733 // Set the background color to be blue.
734 webViewThemeLinearLayout.setBackgroundColor(getColor(context, R.color.blue_background))
738 // Set the icon color.
739 webViewThemeImageView.isSelected = false
741 // Hide the WebView theme text view.
742 webViewThemeTextView.visibility = View.GONE
744 // Set the background color to be blue.
745 webViewThemeLinearLayout.setBackgroundColor(getColor(context, R.color.blue_background))
750 // Set the switch positions.
751 pinnedSslCertificateSwitch.isChecked = (pinnedSslCertificateInt == 1)
752 pinnedIpAddressesSwitch.isChecked = (pinnedIpAddressesInt == 1)
754 // Set the switch icon colors.
755 pinnedSslCertificateImageView.isSelected = (pinnedSslCertificateInt == 1)
756 pinnedIpAddressesImageView.isSelected = (pinnedIpAddressesInt == 1)
758 // Store the current date.
759 val currentDate = Calendar.getInstance().time
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)
769 // Initialize the saved SSL certificate date variables.
770 var savedSslStartDate: Date? = null
771 var savedSslEndDate: Date? = null
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)
779 // Create the date spannable string builders.
780 val savedSslStartDateStringBuilder: SpannableStringBuilder = if (savedSslStartDate == null)
781 SpannableStringBuilder(startDateLabel)
783 SpannableStringBuilder(startDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(savedSslStartDate))
785 val savedSslEndDateStringBuilder: SpannableStringBuilder = if (savedSslEndDate == null)
786 SpannableStringBuilder(endDateLabel)
788 SpannableStringBuilder(endDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(savedSslEndDate))
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)
797 // Check the certificate Common Name against the domain name.
798 val savedSslCommonNameMatchesDomainName = checkDomainNameAgainstCertificate(domainNameString, savedSslIssuedToCNameString)
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)
804 savedSslIssuedToCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length, savedSslIssuedToCNameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
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)
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)
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
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)
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))
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)
851 // Check the certificate Common Name against the domain name.
852 val currentSslCommonNameMatchesDomainName = checkDomainNameAgainstCertificate(domainNameString, DomainsActivity.sslIssuedToCName)
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)
858 currentSslIssuedToCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length, currentSslIssuedToCNameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
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)
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)
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
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
889 savedSslCardView.visibility = View.VISIBLE
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
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
902 // Hide the instruction.
903 noCurrentWebsiteCertificateTextView.visibility = View.GONE
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
911 // Uncheck the current website SSL certificate radio button.
912 currentWebsiteCertificateRadioButton.isChecked = false
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
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
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
933 // Uncheck the radio buttons.
934 savedSslCertificateRadioButton.isChecked = false
935 currentWebsiteCertificateRadioButton.isChecked = false
938 // Populate the saved and current IP addresses.
939 savedIpAddressesTextView.text = savedIpAddresses
940 currentIpAddressesTextView.text = DomainsActivity.currentIpAddresses
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
950 // Set the visibility of the current IP addresses.
951 currentIpAddressesCardView.visibility = View.VISIBLE
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
958 // Uncheck the current IP addresses radio button.
959 currentIpAddressesRadioButton.isChecked = false
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
967 // Uncheck the saved IP addresses radio button.
968 savedIpAddressesRadioButton.isChecked = false
970 } else { // IP addresses are not pinned.
971 // Hide the IP addresses card views.
972 savedIpAddressesCardView.visibility = View.GONE
973 currentIpAddressesCardView.visibility = View.GONE
975 // Uncheck the radio buttons.
976 savedIpAddressesRadioButton.isChecked = false
977 currentIpAddressesRadioButton.isChecked = false
981 // Set the JavaScript spinner listener.
982 javaScriptSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
983 override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
987 if (javaScriptDefault)
988 javaScriptImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.javascript_enabled, null))
990 javaScriptImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.privacy_mode, null))
992 // Show the text view.
993 javaScriptTextView.visibility = View.VISIBLE
995 // Set the background color to be transparent.
996 javaScriptLinearLayout.setBackgroundColor(getColor(context, R.color.transparent))
1001 javaScriptImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.javascript_enabled, null))
1003 // Hide the text view.
1004 javaScriptTextView.visibility = View.GONE
1006 // Set the background color to be blue.
1007 javaScriptLinearLayout.setBackgroundColor(getColor(context, R.color.blue_background))
1012 javaScriptImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.privacy_mode, null))
1014 // Hide the text view.
1015 javaScriptTextView.visibility = View.GONE
1017 // Set the background color to be blue.
1018 javaScriptLinearLayout.setBackgroundColor(getColor(context, R.color.blue_background))
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))
1025 // Set the DOM storage spinner and text view status based on the JavaScript status.
1026 domStorageSpinner.isEnabled = updatedJavaScriptEnabled
1027 domStorageTextView.isEnabled = updatedJavaScriptEnabled
1029 // Set the DOM storage icon ghosted status based on the JavaScript status.
1030 domStorageImageView.isEnabled = updatedJavaScriptEnabled
1033 override fun onNothingSelected(parent: AdapterView<*>?) {
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)
1045 override fun onNothingSelected(parent: AdapterView<*>?) {
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)
1057 override fun onNothingSelected(parent: AdapterView<*>?) {
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)
1070 override fun onNothingSelected(parent: AdapterView<*>?) {
1076 // Set the EasyList spinner listener.
1077 easyListSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
1078 override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
1079 // Update the icon and the text view settings.
1080 setIconAndTextViewSettings(position, easyListDefault, easyListLinearLayout, easyListImageView, easyListTextView)
1083 override fun onNothingSelected(parent: AdapterView<*>?) {
1088 // Set the EasyPrivacy spinner listener.
1089 easyPrivacySpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
1090 override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
1091 // Update the icon and the text view settings.
1092 setIconAndTextViewSettings(position, easyPrivacyDefault, easyPrivacyLinearLayout, easyPrivacyImageView, easyPrivacyTextView)
1095 override fun onNothingSelected(parent: AdapterView<*>?) {
1100 // Set the Fanboy's Annoyance List spinner listener.
1101 fanboysAnnoyanceListSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
1102 override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
1103 // Update the icon and the text view settings.
1104 setIconAndTextViewSettings(position, fanboysAnnoyanceListDefault, fanboysAnnoyanceListLinearLayout, fanboysAnnoyanceListImageView, fanboysAnnoyanceListTextView)
1106 // 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.
1107 val updatedFanboysAnnoyanceListEnabled = (((position == 0) && fanboysAnnoyanceListDefault) || (position == 1))
1109 // Set Fanboy's Social Blocking List spinner and test view status based on the Annoyance List status.
1110 fanboysSocialBlockingListSpinner.isEnabled = !updatedFanboysAnnoyanceListEnabled
1111 fanboysSocialBlockingListTextView.isEnabled = !updatedFanboysAnnoyanceListEnabled
1113 // Set the Social Blocking List icon ghosted status based on the Annoyance List status.
1114 fanboysSocialBlockingListImageView.isEnabled = !updatedFanboysAnnoyanceListEnabled
1117 override fun onNothingSelected(parent: AdapterView<*>?) {
1122 // Set the Fanboy's Social Blocking List spinner listener.
1123 fanboysSocialBlockingListSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
1124 override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
1125 // Update the icon and the text view settings.
1126 setIconAndTextViewSettings(position, fanboysSocialBlockingListDefault, fanboysSocialBlockingListLinearLayout, fanboysSocialBlockingListImageView, fanboysSocialBlockingListTextView)
1129 override fun onNothingSelected(parent: AdapterView<*>?) {
1134 // Set the UltraList spinner listener.
1135 ultraListSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
1136 override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
1137 // Update the icon and the text view settings.
1138 setIconAndTextViewSettings(position, ultraListDefault, ultraListLinearLayout, ultraListImageView, ultraListTextView)
1141 override fun onNothingSelected(parent: AdapterView<*>?) {
1146 // Set the UltraPrivacy spinner listener.
1147 ultraPrivacySpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
1148 override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
1149 // Update the icon and the text view settings.
1150 setIconAndTextViewSettings(position, ultraPrivacyDefault, ultraPrivacyLinearLayout, ultraPrivacyImageView, ultraPrivacyTextView)
1153 override fun onNothingSelected(parent: AdapterView<*>?) {
1158 // Set the block all third-party requests spinner listener.
1159 blockAllThirdPartyRequestsSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
1160 override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
1161 // Update the icon and the text view settings.
1162 setIconAndTextViewSettings(position, blockAllThirdPartyRequestsDefault, blockAllThirdPartyRequestsLinearLayout, blockAllThirdPartyRequestsImageView, blockAllThirdPartyRequestsTextView)
1165 override fun onNothingSelected(parent: AdapterView<*>?) {
1170 // Set the user agent spinner listener.
1171 userAgentSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
1172 override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
1173 // Set the new user agent.
1175 DOMAINS_SYSTEM_DEFAULT_USER_AGENT -> {
1176 // Show the user agent text view.
1177 userAgentTextView.visibility = View.VISIBLE
1179 // Hide the custom user agent edit text.
1180 customUserAgentEditText.visibility = View.GONE
1182 // Set the user text.
1183 when (defaultUserAgentArrayPosition) {
1184 // This is probably because it was set in an older version of Privacy Browser before the switch to persistent user agent names.
1185 UNRECOGNIZED_USER_AGENT -> userAgentTextView.text = userAgentDefault
1187 // Display the `WebView` default user agent.
1188 SETTINGS_WEBVIEW_DEFAULT_USER_AGENT -> userAgentTextView.text = webViewDefaultUserAgentString
1190 // Display the custom user agent.
1191 SETTINGS_CUSTOM_USER_AGENT -> userAgentTextView.text = customUserAgentStringDefault
1193 // Get the user agent string from the user agent data array.
1194 else -> userAgentTextView.text = userAgentDataArray[defaultUserAgentArrayPosition]
1197 // Set the background color to be transparent.
1198 userAgentLinearLayout.setBackgroundColor(getColor(context, R.color.transparent))
1201 DOMAINS_WEBVIEW_DEFAULT_USER_AGENT -> {
1202 // Show the user agent text view.
1203 userAgentTextView.visibility = View.VISIBLE
1205 // Set the user agent text.
1206 userAgentTextView.text = webViewDefaultUserAgentString
1208 // Hide the custom user agent edit text.
1209 customUserAgentEditText.visibility = View.GONE
1211 // Set the background color to be blue.
1212 userAgentLinearLayout.setBackgroundColor(getColor(context, R.color.blue_background))
1215 DOMAINS_CUSTOM_USER_AGENT -> {
1216 // Hide the user agent text view.
1217 userAgentTextView.visibility = View.GONE
1219 // Show the custom user agent edit text.
1220 customUserAgentEditText.visibility = View.VISIBLE
1222 // Set the current user agent name as the text.
1223 customUserAgentEditText.setText(currentUserAgentName)
1225 // Set the background color to be blue.
1226 userAgentLinearLayout.setBackgroundColor(getColor(context, R.color.blue_background))
1230 // Show the user agent text view.
1231 userAgentTextView.visibility = View.VISIBLE
1233 // Set the text from the user agent data array, which has one less entry than the spinner, so the position must be decremented.
1234 userAgentTextView.text = userAgentDataArray[position - 1]
1236 // Hide the custom user agent edit text.
1237 customUserAgentEditText.visibility = View.GONE
1239 // Set the background color to be blue.
1240 userAgentLinearLayout.setBackgroundColor(getColor(context, R.color.blue_background))
1245 override fun onNothingSelected(parent: AdapterView<*>?) {
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
1258 // Hide the custom font size edit text.
1259 customFontSizeEditText.visibility = View.GONE
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
1267 // Show the custom font size edit text.
1268 customFontSizeEditText.visibility = View.VISIBLE
1270 // Set the background color to be blue.
1271 fontSizeLinearLayout.setBackgroundColor(getColor(context, R.color.blue_background))
1275 override fun onNothingSelected(parent: AdapterView<*>?) {
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)
1287 override fun onNothingSelected(parent: AdapterView<*>?) {
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.
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
1305 // Show the WebView theme text view.
1306 webViewThemeTextView.visibility = View.VISIBLE
1308 // Set the background color to be transparent.
1309 webViewThemeLinearLayout.setBackgroundColor(getColor(context, R.color.transparent))
1313 // Set the icon color.
1314 webViewThemeImageView.isSelected = true
1316 // Hide the WebView theme text view.
1317 webViewThemeTextView.visibility = View.GONE
1319 // Set the background color to be blue.
1320 webViewThemeLinearLayout.setBackgroundColor(getColor(context, R.color.blue_background))
1324 // Set the icon color.
1325 webViewThemeImageView.isSelected = false
1327 // Hide the WebView theme text view.
1328 webViewThemeTextView.visibility = View.GONE
1330 // Set the background color to be blue.
1331 webViewThemeLinearLayout.setBackgroundColor(getColor(context, R.color.blue_background))
1336 override fun onNothingSelected(parent: AdapterView<*>?) {
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)
1348 override fun onNothingSelected(parent: AdapterView<*>?) {
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)
1360 override fun onNothingSelected(parent: AdapterView<*>?) {
1365 // Set the pinned SSL certificate switch listener.
1366 pinnedSslCertificateSwitch.setOnCheckedChangeListener { _: CompoundButton?, isChecked: Boolean ->
1367 // Update the icon color.
1368 pinnedSslCertificateImageView.isSelected = isChecked
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
1376 savedSslCardView.visibility = View.VISIBLE
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
1383 // Show the instruction.
1384 noCurrentWebsiteCertificateTextView.visibility = View.VISIBLE
1386 // Show the SSL certificate.
1387 currentSslCardView.visibility = View.VISIBLE
1389 // Hide the instruction.
1390 noCurrentWebsiteCertificateTextView.visibility = View.GONE
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
1398 // Uncheck the current website SSL certificate radio button.
1399 currentWebsiteCertificateRadioButton.isChecked = false
1401 // Set the background of the saved SSL certificate linear layout to be transparent.
1402 savedSslCertificateLinearLayout.setBackgroundResource(R.color.transparent)
1404 // Darken the background of the current website SSL certificate linear layout according to the theme.
1405 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.translucent_background)
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
1413 // Uncheck the saved SSL certificate radio button.
1414 savedSslCertificateRadioButton.isChecked = false
1416 // Set the background of the current website SSL certificate linear layout to be transparent.
1417 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.transparent)
1419 // Darken the background of the saved SSL certificate linear layout according to the theme.
1420 savedSslCertificateLinearLayout.setBackgroundResource(R.color.translucent_background)
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
1429 // Scroll to the current website SSL certificate card.
1430 noCurrentWebsiteCertificateTextView.parent.requestChildFocus(noCurrentWebsiteCertificateTextView, noCurrentWebsiteCertificateTextView)
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
1438 // Uncheck the radio buttons.
1439 savedSslCertificateRadioButton.isChecked = false
1440 currentWebsiteCertificateRadioButton.isChecked = false
1444 // Set the saved SSL card view listener.
1445 savedSslCardView.setOnClickListener {
1446 // Check the saved SSL certificate radio button.
1447 savedSslCertificateRadioButton.isChecked = true
1449 // Uncheck the current website SSL certificate radio button.
1450 currentWebsiteCertificateRadioButton.isChecked = false
1452 // Set the background of the saved SSL certificate linear layout to be transparent.
1453 savedSslCertificateLinearLayout.setBackgroundResource(R.color.transparent)
1455 // Darken the background of the current website SSL certificate linear layout.
1456 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.translucent_background)
1459 // Set the saved SSL certificate radio button listener.
1460 savedSslCertificateRadioButton.setOnClickListener {
1461 // Check the saved SSL certificate radio button.
1462 savedSslCertificateRadioButton.isChecked = true
1464 // Uncheck the current website SSL certificate radio button.
1465 currentWebsiteCertificateRadioButton.isChecked = false
1467 // Set the background of the saved SSL certificate linear layout to be transparent.
1468 savedSslCertificateLinearLayout.setBackgroundResource(R.color.transparent)
1470 // Darken the background of the current website SSL certificate linear layout.
1471 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.translucent_background)
1474 // Set the current SSL card view listener.
1475 currentSslCardView.setOnClickListener {
1476 // Check the current website SSL certificate radio button.
1477 currentWebsiteCertificateRadioButton.isChecked = true
1479 // Uncheck the saved SSL certificate radio button.
1480 savedSslCertificateRadioButton.isChecked = false
1482 // Set the background of the current website SSL certificate linear layout to be transparent.
1483 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.transparent)
1485 // Darken the background of the saved SSL certificate linear layout.
1486 savedSslCertificateLinearLayout.setBackgroundResource(R.color.translucent_background)
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
1494 // Uncheck the saved SSL certificate radio button.
1495 savedSslCertificateRadioButton.isChecked = false
1497 // Set the background of the current website SSL certificate linear layout to be transparent.
1498 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.transparent)
1500 // Darken the background of the saved SSL certificate linear layout.
1501 savedSslCertificateLinearLayout.setBackgroundResource(R.color.translucent_background)
1504 // Set the pinned IP addresses switch listener.
1505 pinnedIpAddressesSwitch.setOnCheckedChangeListener { _: CompoundButton?, isChecked: Boolean ->
1506 // Update the icon color.
1507 pinnedIpAddressesImageView.isSelected = isChecked
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
1515 savedIpAddressesCardView.visibility = View.VISIBLE
1517 // Show the current IP addresses card view.
1518 currentIpAddressesCardView.visibility = View.VISIBLE
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
1525 // Uncheck the current IP addresses radio button.
1526 currentIpAddressesRadioButton.isChecked = false
1528 // Set the background of the saved IP addresses linear layout to be transparent.
1529 savedSslCertificateLinearLayout.setBackgroundResource(R.color.transparent)
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
1537 // Uncheck the saved IP addresses radio button.
1538 savedIpAddressesRadioButton.isChecked = false
1540 // Set the background of the current IP addresses linear layout to be transparent.
1541 currentIpAddressesLinearLayout.setBackgroundResource(R.color.transparent)
1543 // Darken the background of the saved IP addresses linear layout.
1544 savedIpAddressesLinearLayout.setBackgroundResource(R.color.translucent_background)
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
1554 // Uncheck the radio buttons.
1555 savedIpAddressesRadioButton.isChecked = false
1556 currentIpAddressesRadioButton.isChecked = false
1560 // Set the saved IP addresses card view listener.
1561 savedIpAddressesCardView.setOnClickListener {
1562 // Check the saved IP addresses radio button.
1563 savedIpAddressesRadioButton.isChecked = true
1565 // Uncheck the current website IP addresses radio button.
1566 currentIpAddressesRadioButton.isChecked = false
1568 // Set the background of the saved IP addresses linear layout to be transparent.
1569 savedIpAddressesLinearLayout.setBackgroundResource(R.color.transparent)
1571 // Darken the background of the current IP addresses linear layout.
1572 currentIpAddressesLinearLayout.setBackgroundResource(R.color.translucent_background)
1575 // Set the saved IP addresses radio button listener.
1576 savedIpAddressesRadioButton.setOnClickListener {
1577 // Check the saved IP addresses radio button.
1578 savedIpAddressesRadioButton.isChecked = true
1580 // Uncheck the current website IP addresses radio button.
1581 currentIpAddressesRadioButton.isChecked = false
1583 // Set the background of the saved IP addresses linear layout to be transparent.
1584 savedIpAddressesLinearLayout.setBackgroundResource(R.color.transparent)
1586 // Darken the background of the current IP addresses linear layout.
1587 currentIpAddressesLinearLayout.setBackgroundResource(R.color.translucent_background)
1590 // Set the current IP addresses card view listener.
1591 currentIpAddressesCardView.setOnClickListener {
1592 // Check the current IP addresses radio button.
1593 currentIpAddressesRadioButton.isChecked = true
1595 // Uncheck the saved IP addresses radio button.
1596 savedIpAddressesRadioButton.isChecked = false
1598 // Set the background of the current IP addresses linear layout to be transparent.
1599 currentIpAddressesLinearLayout.setBackgroundResource(R.color.transparent)
1601 // Darken the background of the saved IP addresses linear layout.
1602 savedIpAddressesLinearLayout.setBackgroundResource(R.color.translucent_background)
1605 // Set the current IP addresses radio button listener.
1606 currentIpAddressesRadioButton.setOnClickListener {
1607 // Check the current IP addresses radio button.
1608 currentIpAddressesRadioButton.isChecked = true
1610 // Uncheck the saved IP addresses radio button.
1611 savedIpAddressesRadioButton.isChecked = false
1613 // Set the background of the current IP addresses linear layout to be transparent.
1614 currentIpAddressesLinearLayout.setBackgroundResource(R.color.transparent)
1616 // Darken the background of the saved IP addresses linear layout.
1617 savedIpAddressesLinearLayout.setBackgroundResource(R.color.translucent_background)
1620 // Set the scroll Y.
1621 domainSettingsScrollView.post { domainSettingsScrollView.scrollY = scrollY }
1623 // Return the domain settings view.
1624 return domainSettingsView
1627 private fun checkDomainNameAgainstCertificate(domainName: String?, certificateCommonName: String?): Boolean {
1628 // Initialize the domain names match tracker.
1629 var domainNamesMatch = false
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
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)
1642 // Create a copy of the certificate Common Name to test subdomains.
1643 var certificateCommonNameSubdomain: String = certificateCommonName
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
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.
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)
1665 // Setup a copy of domain name to test subdomains.
1666 var domainNameSubdomain: String = domainName
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
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.
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)
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
1695 return domainNamesMatch
1698 private fun populateTextView(defaultValue: Boolean, arrayAdapter: ArrayAdapter<CharSequence>, textView: TextView) {
1700 textView.text = if (defaultValue)
1701 arrayAdapter.getItem(ENABLED)
1703 arrayAdapter.getItem(DISABLED)
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) {
1710 // Set the icon color.
1711 imageView.isSelected = defaultValue
1713 // Show the text view.
1714 textView.visibility = View.VISIBLE
1716 // Set the background color to be transparent.
1717 linearLayout.setBackgroundColor(getColor(context, R.color.transparent))
1721 // Set the icon color.
1722 imageView.isSelected = true
1724 // Hide the text view.
1725 textView.visibility = View.GONE
1727 // Set the background color to be blue.
1728 linearLayout.setBackgroundColor(getColor(context, R.color.blue_background))
1732 // Set the icon color.
1733 imageView.isSelected = false
1735 // Hide the text view.
1736 textView.visibility = View.GONE
1738 // Set the background color to be blue.
1739 linearLayout.setBackgroundColor(getColor(context, R.color.blue_background))