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 // Hide the WebView theme linear layout if the API < 29.
273 if (Build.VERSION.SDK_INT < 29)
274 webViewThemeLinearLayout.visibility = View.GONE
276 // Initialize the database handler.
277 val domainsDatabaseHelper = DomainsDatabaseHelper(requireContext())
279 // Get the database cursor for this ID.
280 val domainCursor = domainsDatabaseHelper.getCursorForId(databaseId)
282 // Move to the first row.
283 domainCursor.moveToFirst()
285 // Save the cursor entries as variables.
286 val domainNameString = domainCursor.getString(domainCursor.getColumnIndexOrThrow(DOMAIN_NAME))
287 val javaScriptInt = domainCursor.getInt(domainCursor.getColumnIndexOrThrow(ENABLE_JAVASCRIPT))
288 val cookiesInt = domainCursor.getInt(domainCursor.getColumnIndexOrThrow(COOKIES))
289 val domStorageInt = domainCursor.getInt(domainCursor.getColumnIndexOrThrow(ENABLE_DOM_STORAGE))
290 val formDataInt = domainCursor.getInt(domainCursor.getColumnIndexOrThrow(ENABLE_FORM_DATA)) // Form data can be remove once the minimum API >= 26.
291 val easyListInt = domainCursor.getInt(domainCursor.getColumnIndexOrThrow(ENABLE_EASYLIST))
292 val easyPrivacyInt = domainCursor.getInt(domainCursor.getColumnIndexOrThrow(ENABLE_EASYPRIVACY))
293 val fanboysAnnoyanceListInt = domainCursor.getInt(domainCursor.getColumnIndexOrThrow(ENABLE_FANBOYS_ANNOYANCE_LIST))
294 val fanboysSocialBlockingListInt = domainCursor.getInt(domainCursor.getColumnIndexOrThrow(ENABLE_FANBOYS_SOCIAL_BLOCKING_LIST))
295 val ultraListInt = domainCursor.getInt(domainCursor.getColumnIndexOrThrow(ULTRALIST))
296 val ultraPrivacyInt = domainCursor.getInt(domainCursor.getColumnIndexOrThrow(ENABLE_ULTRAPRIVACY))
297 val blockAllThirdPartyRequestsInt = domainCursor.getInt(domainCursor.getColumnIndexOrThrow(BLOCK_ALL_THIRD_PARTY_REQUESTS))
298 val currentUserAgentName = domainCursor.getString(domainCursor.getColumnIndexOrThrow(USER_AGENT))
299 val fontSizeInt = domainCursor.getInt(domainCursor.getColumnIndexOrThrow(FONT_SIZE))
300 val swipeToRefreshInt = domainCursor.getInt(domainCursor.getColumnIndexOrThrow(SWIPE_TO_REFRESH))
301 val webViewThemeInt = domainCursor.getInt(domainCursor.getColumnIndexOrThrow(WEBVIEW_THEME))
302 val wideViewportInt = domainCursor.getInt(domainCursor.getColumnIndexOrThrow(WIDE_VIEWPORT))
303 val displayImagesInt = domainCursor.getInt(domainCursor.getColumnIndexOrThrow(DISPLAY_IMAGES))
304 val pinnedSslCertificateInt = domainCursor.getInt(domainCursor.getColumnIndexOrThrow(PINNED_SSL_CERTIFICATE))
305 val savedSslIssuedToCNameString = domainCursor.getString(domainCursor.getColumnIndexOrThrow(SSL_ISSUED_TO_COMMON_NAME))
306 val savedSslIssuedToONameString = domainCursor.getString(domainCursor.getColumnIndexOrThrow(SSL_ISSUED_TO_ORGANIZATION))
307 val savedSslIssuedToUNameString = domainCursor.getString(domainCursor.getColumnIndexOrThrow(SSL_ISSUED_TO_ORGANIZATIONAL_UNIT))
308 val savedSslIssuedByCNameString = domainCursor.getString(domainCursor.getColumnIndexOrThrow(SSL_ISSUED_BY_COMMON_NAME))
309 val savedSslIssuedByONameString = domainCursor.getString(domainCursor.getColumnIndexOrThrow(SSL_ISSUED_BY_ORGANIZATION))
310 val savedSslIssuedByUNameString = domainCursor.getString(domainCursor.getColumnIndexOrThrow(SSL_ISSUED_BY_ORGANIZATIONAL_UNIT))
311 val savedSslStartDateLong = domainCursor.getLong(domainCursor.getColumnIndexOrThrow(SSL_START_DATE))
312 val savedSslEndDateLong = domainCursor.getLong(domainCursor.getColumnIndexOrThrow(SSL_END_DATE))
313 val pinnedIpAddressesInt = domainCursor.getInt(domainCursor.getColumnIndexOrThrow(PINNED_IP_ADDRESSES))
314 val savedIpAddresses = domainCursor.getString(domainCursor.getColumnIndexOrThrow(IP_ADDRESSES))
316 // Close the domain cursor.
319 // Create spinner array adapters.
320 val javaScriptArrayAdapter = ArrayAdapter.createFromResource(context, R.array.javascript_array, R.layout.spinner_item)
321 val cookiesArrayAdapter = ArrayAdapter.createFromResource(context, R.array.cookies_array, R.layout.spinner_item)
322 val domStorageArrayAdapter = ArrayAdapter.createFromResource(context, R.array.dom_storage_array, R.layout.spinner_item)
323 val formDataArrayAdapter = ArrayAdapter.createFromResource(context, R.array.form_data_array, R.layout.spinner_item) // Form data can be remove once the minimum API >= 26.
324 val easyListArrayAdapter = ArrayAdapter.createFromResource(context, R.array.easylist_array, R.layout.spinner_item)
325 val easyPrivacyArrayAdapter = ArrayAdapter.createFromResource(context, R.array.easyprivacy_array, R.layout.spinner_item)
326 val fanboysAnnoyanceListArrayAdapter = ArrayAdapter.createFromResource(context, R.array.fanboys_annoyance_list_array, R.layout.spinner_item)
327 val fanboysSocialBlockingListArrayAdapter = ArrayAdapter.createFromResource(context, R.array.fanboys_social_blocking_list_array, R.layout.spinner_item)
328 val ultraListArrayAdapter = ArrayAdapter.createFromResource(context, R.array.ultralist_array, R.layout.spinner_item)
329 val ultraPrivacyArrayAdapter = ArrayAdapter.createFromResource(context, R.array.ultraprivacy_array, R.layout.spinner_item)
330 val blockAllThirdPartyRequestsArrayAdapter = ArrayAdapter.createFromResource(context, R.array.block_all_third_party_requests_array, R.layout.spinner_item)
331 val translatedUserAgentArrayAdapter = ArrayAdapter.createFromResource(context, R.array.translated_domain_settings_user_agent_names, R.layout.spinner_item)
332 val fontSizeArrayAdapter = ArrayAdapter.createFromResource(context, R.array.font_size_array, R.layout.spinner_item)
333 val swipeToRefreshArrayAdapter = ArrayAdapter.createFromResource(context, R.array.swipe_to_refresh_array, R.layout.spinner_item)
334 val webViewThemeArrayAdapter = ArrayAdapter.createFromResource(context, R.array.webview_theme_array, R.layout.spinner_item)
335 val wideViewportArrayAdapter = ArrayAdapter.createFromResource(context, R.array.wide_viewport_array, R.layout.spinner_item)
336 val displayImagesArrayAdapter = ArrayAdapter.createFromResource(context, R.array.display_webpage_images_array, R.layout.spinner_item)
338 // Set the drop down view resource on the spinners.
339 javaScriptArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items)
340 cookiesArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items)
341 domStorageArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items)
342 formDataArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items) // Form data can be remove once the minimum API >= 26.
343 easyListArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items)
344 easyPrivacyArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items)
345 fanboysAnnoyanceListArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items)
346 fanboysSocialBlockingListArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items)
347 ultraListArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items)
348 ultraPrivacyArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items)
349 blockAllThirdPartyRequestsArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items)
350 translatedUserAgentArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items)
351 fontSizeArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items)
352 swipeToRefreshArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items)
353 webViewThemeArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items)
354 wideViewportArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items)
355 displayImagesArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items)
357 // Set the array adapters for the spinners.
358 javaScriptSpinner.adapter = javaScriptArrayAdapter
359 cookiesSpinner.adapter = cookiesArrayAdapter
360 domStorageSpinner.adapter = domStorageArrayAdapter
361 formDataSpinner.adapter = formDataArrayAdapter // Form data can be remove once the minimum API >= 26.
362 easyListSpinner.adapter = easyListArrayAdapter
363 easyPrivacySpinner.adapter = easyPrivacyArrayAdapter
364 fanboysAnnoyanceListSpinner.adapter = fanboysAnnoyanceListArrayAdapter
365 fanboysSocialBlockingListSpinner.adapter = fanboysSocialBlockingListArrayAdapter
366 ultraListSpinner.adapter = ultraListArrayAdapter
367 ultraPrivacySpinner.adapter = ultraPrivacyArrayAdapter
368 blockAllThirdPartyRequestsSpinner.adapter = blockAllThirdPartyRequestsArrayAdapter
369 userAgentSpinner.adapter = translatedUserAgentArrayAdapter
370 fontSizeSpinner.adapter = fontSizeArrayAdapter
371 swipeToRefreshSpinner.adapter = swipeToRefreshArrayAdapter
372 webViewThemeSpinner.adapter = webViewThemeArrayAdapter
373 wideViewportSpinner.adapter = wideViewportArrayAdapter
374 displayImagesSpinner.adapter = displayImagesArrayAdapter
376 // Open the spinners when the text view is tapped.
377 javaScriptTextView.setOnClickListener { javaScriptSpinner.performClick() }
378 cookiesTextView.setOnClickListener { cookiesSpinner.performClick() }
379 domStorageTextView.setOnClickListener { domStorageSpinner.performClick() }
380 formDataTextView.setOnClickListener { formDataSpinner.performClick() }
381 easyListTextView.setOnClickListener { easyListSpinner.performClick() }
382 easyPrivacyTextView.setOnClickListener { easyPrivacySpinner.performClick() }
383 fanboysAnnoyanceListTextView.setOnClickListener { fanboysAnnoyanceListSpinner.performClick() }
384 fanboysSocialBlockingListTextView.setOnClickListener { fanboysSocialBlockingListSpinner.performClick() }
385 ultraListTextView.setOnClickListener { ultraListSpinner.performClick() }
386 ultraPrivacyTextView.setOnClickListener { ultraPrivacySpinner.performClick() }
387 blockAllThirdPartyRequestsTextView.setOnClickListener { blockAllThirdPartyRequestsSpinner.performClick() }
388 userAgentTextView.setOnClickListener { userAgentSpinner.performClick() }
389 defaultFontSizeTextView.setOnClickListener { fontSizeSpinner.performClick() }
390 swipeToRefreshTextView.setOnClickListener { swipeToRefreshSpinner.performClick() }
391 webViewThemeTextView.setOnClickListener { webViewThemeSpinner.performClick() }
392 wideViewportTextView.setOnClickListener { wideViewportSpinner.performClick() }
393 displayImagesTextView.setOnClickListener { displayImagesSpinner.performClick() }
395 // Set the spinner selections. Items that aren't defined by an integer are handled individually below.
396 javaScriptSpinner.setSelection(javaScriptInt)
397 cookiesSpinner.setSelection(cookiesInt)
398 domStorageSpinner.setSelection(domStorageInt)
399 formDataSpinner.setSelection(formDataInt)
400 easyListSpinner.setSelection(easyListInt)
401 easyPrivacySpinner.setSelection(easyPrivacyInt)
402 fanboysAnnoyanceListSpinner.setSelection(fanboysAnnoyanceListInt)
403 fanboysSocialBlockingListSpinner.setSelection(fanboysSocialBlockingListInt)
404 ultraListSpinner.setSelection(ultraListInt)
405 ultraPrivacySpinner.setSelection(ultraPrivacyInt)
406 blockAllThirdPartyRequestsSpinner.setSelection(blockAllThirdPartyRequestsInt)
407 swipeToRefreshSpinner.setSelection(swipeToRefreshInt)
408 webViewThemeSpinner.setSelection(webViewThemeInt)
409 wideViewportSpinner.setSelection(wideViewportInt)
410 displayImagesSpinner.setSelection(displayImagesInt)
412 // Populate the text views. Items that aren't defined by an integer are handled individually below.
413 populateTextView(javaScriptDefault, javaScriptArrayAdapter, javaScriptTextView)
414 populateTextView(cookiesDefault, cookiesArrayAdapter, cookiesTextView)
415 populateTextView(domStorageDefault, domStorageArrayAdapter, domStorageTextView)
416 populateTextView(formDataDefault, formDataArrayAdapter, formDataTextView)
417 populateTextView(easyListDefault, easyListArrayAdapter, easyListTextView)
418 populateTextView(easyPrivacyDefault, easyPrivacyArrayAdapter, easyPrivacyTextView)
419 populateTextView(fanboysAnnoyanceListDefault, fanboysAnnoyanceListArrayAdapter, fanboysAnnoyanceListTextView)
420 populateTextView(fanboysSocialBlockingListDefault, fanboysSocialBlockingListArrayAdapter, fanboysSocialBlockingListTextView)
421 populateTextView(ultraListDefault, ultraListArrayAdapter, ultraListTextView)
422 populateTextView(ultraPrivacyDefault, ultraPrivacyArrayAdapter, ultraPrivacyTextView)
423 populateTextView(blockAllThirdPartyRequestsDefault, blockAllThirdPartyRequestsArrayAdapter, blockAllThirdPartyRequestsTextView)
424 populateTextView(swipeToRefreshDefault, swipeToRefreshArrayAdapter, swipeToRefreshTextView)
425 populateTextView(wideViewportDefault, wideViewportArrayAdapter, wideViewportTextView)
426 populateTextView(displayWebpageImagesDefault, displayImagesArrayAdapter, displayImagesTextView)
428 // Set the icon and text view settings. Non-standard items are handled individually below.
429 setIconAndTextViewSettings(cookiesInt, cookiesDefault, cookiesLinearLayout, cookiesImageView, cookiesTextView)
430 setIconAndTextViewSettings(domStorageInt, domStorageDefault, domStorageLinearLayout, domStorageImageView, domStorageTextView)
431 setIconAndTextViewSettings(formDataInt, formDataDefault, formDataLinearLayout, formDataImageView, formDataTextView)
432 setIconAndTextViewSettings(easyListInt, easyListDefault, easyListLinearLayout, easyListImageView, easyListTextView)
433 setIconAndTextViewSettings(easyPrivacyInt, easyPrivacyDefault, easyPrivacyLinearLayout, easyPrivacyImageView, easyListTextView)
434 setIconAndTextViewSettings(fanboysAnnoyanceListInt, fanboysAnnoyanceListDefault, fanboysAnnoyanceListLinearLayout, fanboysAnnoyanceListImageView, fanboysAnnoyanceListTextView)
435 setIconAndTextViewSettings(fanboysSocialBlockingListInt, fanboysSocialBlockingListDefault, fanboysSocialBlockingListLinearLayout, fanboysSocialBlockingListImageView, fanboysSocialBlockingListTextView)
436 setIconAndTextViewSettings(ultraListInt, ultraListDefault, ultraListLinearLayout, ultraListImageView, ultraListTextView)
437 setIconAndTextViewSettings(ultraPrivacyInt, ultraPrivacyDefault, ultraPrivacyLinearLayout, ultraPrivacyImageView, ultraPrivacyTextView)
438 setIconAndTextViewSettings(blockAllThirdPartyRequestsInt, blockAllThirdPartyRequestsDefault, blockAllThirdPartyRequestsLinearLayout, blockAllThirdPartyRequestsImageView,
439 blockAllThirdPartyRequestsTextView)
440 setIconAndTextViewSettings(swipeToRefreshInt, swipeToRefreshDefault, swipeToRefreshLinearLayout, swipeToRefreshImageView, swipeToRefreshTextView)
441 setIconAndTextViewSettings(wideViewportInt, wideViewportDefault, wideViewportLinearLayout, wideViewportImageView, wideViewportTextView)
442 setIconAndTextViewSettings(displayImagesInt, displayWebpageImagesDefault, displayImagesLinearLayout, displayImagesImageView, displayImagesTextView)
445 // Set the domain name from the the database cursor.
446 domainNameEditText.setText(domainNameString)
448 // Setup the pinned labels.
449 val cNameLabel = getString(R.string.common_name)
450 val oNameLabel = getString(R.string.organization)
451 val uNameLabel = getString(R.string.organizational_unit)
452 val startDateLabel = getString(R.string.start_date)
453 val endDateLabel = getString(R.string.end_date)
455 // Create the color spans.
456 val blueColorSpan = ForegroundColorSpan(context.getColor(R.color.alt_blue_text))
457 val redColorSpan = ForegroundColorSpan(context.getColor(R.color.red_text))
459 // Update the certificates' Common Name color when the domain name text changes.
460 domainNameEditText.addTextChangedListener(object : TextWatcher {
461 override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
465 override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
469 override fun afterTextChanged(s: Editable) {
470 // Get the new domain name.
471 val newDomainName = domainNameEditText.text.toString()
473 // Check the saved SSL certificate against the new domain name.
474 val savedSslMatchesNewDomainName = checkDomainNameAgainstCertificate(newDomainName, savedSslIssuedToCNameString)
476 // Create a spannable string builder for the saved certificate's Common Name.
477 val savedSslCNameStringBuilder = SpannableStringBuilder(cNameLabel + savedSslIssuedToCNameString)
479 // Format the saved certificate's Common Name color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
480 if (savedSslMatchesNewDomainName) {
481 savedSslCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length, savedSslCNameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
483 savedSslCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length, savedSslCNameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
486 // Update the saved SSL issued to CName text view.
487 savedSslIssuedToCNameTextView.text = savedSslCNameStringBuilder
489 // Update the current website certificate if it exists.
490 if (DomainsActivity.sslIssuedToCName != null) {
491 // Check the current website certificate against the new domain name.
492 val currentSslMatchesNewDomainName = checkDomainNameAgainstCertificate(newDomainName, DomainsActivity.sslIssuedToCName)
494 // Create a spannable string builder for the current website certificate's Common Name.
495 val currentSslCNameStringBuilder = SpannableStringBuilder(cNameLabel + DomainsActivity.sslIssuedToCName)
497 // Format the current certificate Common Name color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
498 if (currentSslMatchesNewDomainName) {
499 currentSslCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length, currentSslCNameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
501 currentSslCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length, currentSslCNameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
504 // Update the current SSL issued to CName text view.
505 currentSslIssuedToCNameTextView.text = currentSslCNameStringBuilder
511 // Set the javaScript icon and text view settings.
512 when (javaScriptInt) {
515 if (javaScriptDefault)
516 javaScriptImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.javascript_enabled, null))
518 javaScriptImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.privacy_mode, null))
520 // Show the text view.
521 javaScriptTextView.visibility = View.VISIBLE
523 // Set the background color to be transparent.
524 javaScriptLinearLayout.setBackgroundColor(getColor(context, R.color.transparent))
529 javaScriptImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.javascript_enabled, null))
531 // Hide the text view.
532 javaScriptTextView.visibility = View.GONE
534 // Set the background color to be blue.
535 javaScriptLinearLayout.setBackgroundColor(getColor(context, R.color.blue_background))
540 javaScriptImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.privacy_mode, null))
542 // Hide the text view.
543 javaScriptTextView.visibility = View.GONE
545 // Set the background color to be blue.
546 javaScriptLinearLayout.setBackgroundColor(getColor(context, R.color.blue_background))
551 // Calculate if JavaScript is enabled, either because it is the system default and that default is enabled, or because it is explicitly set to be enabled for this domain.
552 val javaScriptEnabled = (((javaScriptInt == 0) && javaScriptDefault) || (javaScriptInt == 1))
554 // Set the DOM storage spinner and text view status based on the JavaScript status.
555 domStorageSpinner.isEnabled = javaScriptEnabled
556 domStorageTextView.isEnabled = javaScriptEnabled
558 // Set the DOM storage icon ghosted status based on the JavaScript status.
559 domStorageImageView.isEnabled = javaScriptEnabled
562 // Calculate if Fanboy's Annoyance List is enabled, either because it is the system default and that default is enabled, or because it is explicitly set to be enabled for this domain.
563 val fanboysAnnoyanceListEnabled = (((fanboysAnnoyanceListInt == 0) && fanboysAnnoyanceListDefault) || (fanboysAnnoyanceListInt == 1))
565 // Set Fanboy's Social Blocking List spinner and text view status based on the Annoyance List status.
566 fanboysSocialBlockingListSpinner.isEnabled = !fanboysAnnoyanceListEnabled
567 fanboysSocialBlockingListTextView.isEnabled = !fanboysAnnoyanceListEnabled
569 // Set the Social Blocking List icon ghosted status based on the Annoyance List status.
570 fanboysSocialBlockingListImageView.isEnabled = !fanboysAnnoyanceListEnabled
573 // Inflated a WebView to get the default user agent.
574 // `@SuppressLint("InflateParams")` removes the warning about using `null` as the `ViewGroup`, which in this case makes sense because the bare WebView should not be displayed on the screen.
575 @SuppressLint("InflateParams") val bareWebViewLayout = inflater.inflate(R.layout.bare_webview, null, false)
577 // Get a handle for the bare WebView.
578 val bareWebView = bareWebViewLayout.findViewById<WebView>(R.id.bare_webview)
580 // Get the default user agent.
581 val webViewDefaultUserAgentString = bareWebView.settings.userAgentString
583 // Get a handle for the user agent array adapter. This array does not contain the `System default` entry.
584 val userAgentNamesArray = ArrayAdapter.createFromResource(context, R.array.user_agent_names, R.layout.spinner_item)
586 // Get the positions of the user agent and the default user agent.
587 val userAgentArrayPosition = userAgentNamesArray.getPosition(currentUserAgentName)
588 val defaultUserAgentArrayPosition = userAgentNamesArray.getPosition(userAgentDefault)
590 // Get a handle for the user agent data array. This array does not contain the `System default` entry.
591 val userAgentDataArray = resources.getStringArray(R.array.user_agent_data)
593 // Set the user agent text.
594 if (currentUserAgentName == getString(R.string.system_default_user_agent)) { // Use the system default user agent.
595 // Set the user agent according to the system default.
596 when (defaultUserAgentArrayPosition) {
597 // This is probably because it was set in an older version of Privacy Browser before the switch to persistent user agent names.
598 UNRECOGNIZED_USER_AGENT -> userAgentTextView.text = userAgentDefault
600 // Display the WebView default user agent.
601 SETTINGS_WEBVIEW_DEFAULT_USER_AGENT -> userAgentTextView.text = webViewDefaultUserAgentString
603 // Display the custom user agent.
604 SETTINGS_CUSTOM_USER_AGENT -> userAgentTextView.text = customUserAgentStringDefault
606 // Get the user agent string from the user agent data array.
607 else -> userAgentTextView.text = userAgentDataArray[defaultUserAgentArrayPosition]
610 // Set the background color to be transparent.
611 userAgentLinearLayout.setBackgroundColor(getColor(context, R.color.transparent))
612 } else if (userAgentArrayPosition == UNRECOGNIZED_USER_AGENT || currentUserAgentName == getString(R.string.custom_user_agent)) {
613 // A custom user agent is stored in the current user agent name. The second check is necessary in case the user did not change the default custom text.
614 // Set the user agent spinner to `Custom user agent`.
615 userAgentSpinner.setSelection(DOMAINS_CUSTOM_USER_AGENT)
617 // Hide the user agent text view.
618 userAgentTextView.visibility = View.GONE
620 // Show the custom user agent edit text and set the current user agent name as the text.
621 customUserAgentEditText.visibility = View.VISIBLE
622 customUserAgentEditText.setText(currentUserAgentName)
624 // Set the background color to be blue.
625 userAgentLinearLayout.setBackgroundColor(getColor(context, R.color.blue_background))
626 } else { // The user agent name contains one of the canonical user agents.
627 // Set the user agent spinner selection. The spinner has one more entry at the beginning than the user agent data array, so the position must be incremented.
628 userAgentSpinner.setSelection(userAgentArrayPosition + 1)
630 // Show the user agent text view.
631 userAgentTextView.visibility = View.VISIBLE
633 // Hide the custom user agent edit text.
634 customUserAgentEditText.visibility = View.GONE
636 // Set the user agent text.
637 if (userAgentArrayPosition == DOMAINS_WEBVIEW_DEFAULT_USER_AGENT) { // The WebView default user agent is selected.
638 // Display the WebView default user agent.
639 userAgentTextView.text = webViewDefaultUserAgentString
640 } else { // A user agent besides the default is selected.
641 // Get the user agent string from the user agent data array. The spinner has one more entry at the beginning than the user agent data array, so the position must be incremented.
642 userAgentTextView.text = userAgentDataArray[userAgentArrayPosition + 1]
645 // Set the background color to be blue.
646 userAgentLinearLayout.setBackgroundColor(getColor(context, R.color.blue_background))
650 // Display the font size settings.
651 if (fontSizeInt == SYSTEM_DEFAULT) { // `0` is the code for system default font size.
652 // Set the font size to the system default.
653 fontSizeSpinner.setSelection(SYSTEM_DEFAULT)
655 // Show the default font size text view.
656 defaultFontSizeTextView.visibility = View.VISIBLE
658 // Hide the custom font size edit text.
659 customFontSizeEditText.visibility = View.GONE
661 // Set the default font size as the text of the custom font size edit text. This way, if the user switches to custom it will already be populated.
662 customFontSizeEditText.setText(fontSizeStringDefault)
664 // Set the background color to be transparent.
665 fontSizeLinearLayout.setBackgroundColor(getColor(context, R.color.transparent))
666 } else { // A custom font size is selected.
667 // Set the spinner to the custom font size.
668 fontSizeSpinner.setSelection(1)
670 // Hide the default font size text view.
671 defaultFontSizeTextView.visibility = View.GONE
673 // Show the custom font size edit text.
674 customFontSizeEditText.visibility = View.GONE
676 // Set the custom font size.
677 customFontSizeEditText.setText(fontSizeInt.toString())
679 // Set the background color to be blue.
680 fontSizeLinearLayout.setBackgroundColor(getColor(context, R.color.blue_background))
683 // Initialize the default font size percentage string.
684 val defaultFontSizePercentageString = "$fontSizeStringDefault%"
686 // Set the default font size text in the text view.
687 defaultFontSizeTextView.text = defaultFontSizePercentageString
690 // Get the WebView theme string arrays.
691 val webViewThemeStringArray = resources.getStringArray(R.array.webview_theme_array)
692 val webViewThemeEntryValuesStringArray = resources.getStringArray(R.array.webview_theme_entry_values)
694 // Get the WebView theme entry number that matches the current WebView theme string.
695 val appWebViewThemeEntryNumber = when (webViewThemeDefault) {
696 webViewThemeEntryValuesStringArray[1] -> { LIGHT_THEME } // The light theme is selected.
697 webViewThemeEntryValuesStringArray[2] -> { DARK_THEME } // The dark theme is selected.
698 else -> { SYSTEM_DEFAULT } // The system default theme is selected.
701 // Set the WebView theme text. This is only displayed if system default is selection, but it should be set here in case the user changes the selection.
702 if (appWebViewThemeEntryNumber == SYSTEM_DEFAULT) { // The app WebView theme is system default.
703 // Set the text according to the current UI theme.
704 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO)
705 webViewThemeTextView.text = webViewThemeStringArray[LIGHT_THEME]
707 webViewThemeTextView.text = webViewThemeStringArray[DARK_THEME]
708 } else { // The app WebView theme is not system default.
709 // Set the text according to the app WebView theme.
710 webViewThemeTextView.text = webViewThemeStringArray[appWebViewThemeEntryNumber]
713 // Set the WebView theme icon and text visibility.
714 when (webViewThemeInt) {
716 // Set the icon color.
717 when (appWebViewThemeEntryNumber) {
718 SYSTEM_DEFAULT -> webViewThemeImageView.isSelected = (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO)
719 LIGHT_THEME -> webViewThemeImageView.isSelected = true
720 DARK_THEME -> webViewThemeImageView.isSelected = false
723 // Show the WebView theme text view.
724 webViewThemeTextView.visibility = View.VISIBLE
726 // Set the background color to be transparent.
727 webViewThemeLinearLayout.setBackgroundColor(getColor(context, R.color.transparent))
731 // Set the icon color.
732 webViewThemeImageView.isSelected = true
734 // Hide the WebView theme text view.
735 webViewThemeTextView.visibility = View.GONE
737 // Set the background color to be blue.
738 webViewThemeLinearLayout.setBackgroundColor(getColor(context, R.color.blue_background))
742 // Set the icon color.
743 webViewThemeImageView.isSelected = false
745 // Hide the WebView theme text view.
746 webViewThemeTextView.visibility = View.GONE
748 // Set the background color to be blue.
749 webViewThemeLinearLayout.setBackgroundColor(getColor(context, R.color.blue_background))
754 // Set the switch positions.
755 pinnedSslCertificateSwitch.isChecked = (pinnedSslCertificateInt == 1)
756 pinnedIpAddressesSwitch.isChecked = (pinnedIpAddressesInt == 1)
758 // Set the switch icon colors.
759 pinnedSslCertificateImageView.isSelected = (pinnedSslCertificateInt == 1)
760 pinnedIpAddressesImageView.isSelected = (pinnedIpAddressesInt == 1)
762 // Store the current date.
763 val currentDate = Calendar.getInstance().time
765 // Create a spannable string builder for each text view that needs multiple colors of text.
766 val savedSslIssuedToCNameStringBuilder = SpannableStringBuilder(cNameLabel + savedSslIssuedToCNameString)
767 val savedSslIssuedToONameStringBuilder = SpannableStringBuilder(oNameLabel + savedSslIssuedToONameString)
768 val savedSslIssuedToUNameStringBuilder = SpannableStringBuilder(uNameLabel + savedSslIssuedToUNameString)
769 val savedSslIssuedByCNameStringBuilder = SpannableStringBuilder(cNameLabel + savedSslIssuedByCNameString)
770 val savedSslIssuedByONameStringBuilder = SpannableStringBuilder(oNameLabel + savedSslIssuedByONameString)
771 val savedSslIssuedByUNameStringBuilder = SpannableStringBuilder(uNameLabel + savedSslIssuedByUNameString)
773 // Initialize the saved SSL certificate date variables.
774 var savedSslStartDate: Date? = null
775 var savedSslEndDate: Date? = null
777 // Only get the saved SSL certificate dates from the cursor if they are not set to `0`.
778 if (savedSslStartDateLong != 0L)
779 savedSslStartDate = Date(savedSslStartDateLong)
780 if (savedSslEndDateLong != 0L)
781 savedSslEndDate = Date(savedSslEndDateLong)
783 // Create the date spannable string builders.
784 val savedSslStartDateStringBuilder: SpannableStringBuilder = if (savedSslStartDate == null)
785 SpannableStringBuilder(startDateLabel)
787 SpannableStringBuilder(startDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(savedSslStartDate))
789 val savedSslEndDateStringBuilder: SpannableStringBuilder = if (savedSslEndDate == null)
790 SpannableStringBuilder(endDateLabel)
792 SpannableStringBuilder(endDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(savedSslEndDate))
794 // Setup the string builders to display the general certificate information in blue. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
795 savedSslIssuedToONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length, savedSslIssuedToONameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
796 savedSslIssuedToUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length, savedSslIssuedToUNameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
797 savedSslIssuedByCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length, savedSslIssuedByCNameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
798 savedSslIssuedByONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length, savedSslIssuedByONameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
799 savedSslIssuedByUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length, savedSslIssuedByUNameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
801 // Check the certificate Common Name against the domain name.
802 val savedSslCommonNameMatchesDomainName = checkDomainNameAgainstCertificate(domainNameString, savedSslIssuedToCNameString)
804 // Format the issued to Common Name color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
805 if (savedSslCommonNameMatchesDomainName)
806 savedSslIssuedToCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length, savedSslIssuedToCNameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
808 savedSslIssuedToCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length, savedSslIssuedToCNameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
810 // Format the start date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
811 if (savedSslStartDate != null && savedSslStartDate.after(currentDate)) // The certificate start date is in the future.
812 savedSslStartDateStringBuilder.setSpan(redColorSpan, startDateLabel.length, savedSslStartDateStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
813 else // The certificate start date is in the past.
814 savedSslStartDateStringBuilder.setSpan(blueColorSpan, startDateLabel.length, savedSslStartDateStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
816 // Format the end date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
817 if (savedSslEndDate != null && savedSslEndDate.before(currentDate)) // The certificate end date is in the past.
818 savedSslEndDateStringBuilder.setSpan(redColorSpan, endDateLabel.length, savedSslEndDateStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
819 else // The certificate end date is in the future.
820 savedSslEndDateStringBuilder.setSpan(blueColorSpan, endDateLabel.length, savedSslEndDateStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
822 // Display the saved website SSL certificate strings.
823 savedSslIssuedToCNameTextView.text = savedSslIssuedToCNameStringBuilder
824 savedSslIssuedToONameTextView.text = savedSslIssuedToONameStringBuilder
825 savedSslIssuedToUNameTextView.text = savedSslIssuedToUNameStringBuilder
826 savedSslIssuedByCNameTextView.text = savedSslIssuedByCNameStringBuilder
827 savedSslIssuedByONameTextView.text = savedSslIssuedByONameStringBuilder
828 savedSslIssuedByUNameTextView.text = savedSslIssuedByUNameStringBuilder
829 savedSslStartDateTextView.text = savedSslStartDateStringBuilder
830 savedSslEndDateTextView.text = savedSslEndDateStringBuilder
832 // Populate the current website SSL certificate if there is one.
833 if (DomainsActivity.sslIssuedToCName != null) {
834 // Get dates from the raw long values.
835 val currentSslStartDate = Date(DomainsActivity.sslStartDateLong)
836 val currentSslEndDate = Date(DomainsActivity.sslEndDateLong)
838 // Create a spannable string builder for each text view that needs multiple colors of text.
839 val currentSslIssuedToCNameStringBuilder = SpannableStringBuilder(cNameLabel + DomainsActivity.sslIssuedToCName)
840 val currentSslIssuedToONameStringBuilder = SpannableStringBuilder(oNameLabel + DomainsActivity.sslIssuedToOName)
841 val currentSslIssuedToUNameStringBuilder = SpannableStringBuilder(uNameLabel + DomainsActivity.sslIssuedToUName)
842 val currentSslIssuedByCNameStringBuilder = SpannableStringBuilder(cNameLabel + DomainsActivity.sslIssuedByCName)
843 val currentSslIssuedByONameStringBuilder = SpannableStringBuilder(oNameLabel + DomainsActivity.sslIssuedByOName)
844 val currentSslIssuedByUNameStringBuilder = SpannableStringBuilder(uNameLabel + DomainsActivity.sslIssuedByUName)
845 val currentSslStartDateStringBuilder = SpannableStringBuilder(startDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(currentSslStartDate))
846 val currentSslEndDateStringBuilder = SpannableStringBuilder(endDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(currentSslEndDate))
848 // Setup the string builders to display the general certificate information in blue. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
849 currentSslIssuedToONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length, currentSslIssuedToONameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
850 currentSslIssuedToUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length, currentSslIssuedToUNameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
851 currentSslIssuedByCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length, currentSslIssuedByCNameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
852 currentSslIssuedByONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length, currentSslIssuedByONameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
853 currentSslIssuedByUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length, currentSslIssuedByUNameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
855 // Check the certificate Common Name against the domain name.
856 val currentSslCommonNameMatchesDomainName = checkDomainNameAgainstCertificate(domainNameString, DomainsActivity.sslIssuedToCName)
858 // Format the issued to Common Name color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
859 if (currentSslCommonNameMatchesDomainName)
860 currentSslIssuedToCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length, currentSslIssuedToCNameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
862 currentSslIssuedToCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length, currentSslIssuedToCNameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
864 // Format the start date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
865 if (currentSslStartDate.after(currentDate)) // The certificate start date is in the future.
866 currentSslStartDateStringBuilder.setSpan(redColorSpan, startDateLabel.length, currentSslStartDateStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
867 else // The certificate start date is in the past.
868 currentSslStartDateStringBuilder.setSpan(blueColorSpan, startDateLabel.length, currentSslStartDateStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
870 // Format the end date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
871 if (currentSslEndDate.before(currentDate)) // The certificate end date is in the past.
872 currentSslEndDateStringBuilder.setSpan(redColorSpan, endDateLabel.length, currentSslEndDateStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
873 else // The certificate end date is in the future.
874 currentSslEndDateStringBuilder.setSpan(blueColorSpan, endDateLabel.length, currentSslEndDateStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
876 // Display the current website SSL certificate strings.
877 currentSslIssuedToCNameTextView.text = currentSslIssuedToCNameStringBuilder
878 currentSslIssuedToONameTextView.text = currentSslIssuedToONameStringBuilder
879 currentSslIssuedToUNameTextView.text = currentSslIssuedToUNameStringBuilder
880 currentSslIssuedByCNameTextView.text = currentSslIssuedByCNameStringBuilder
881 currentSslIssuedByONameTextView.text = currentSslIssuedByONameStringBuilder
882 currentSslIssuedByUNameTextView.text = currentSslIssuedByUNameStringBuilder
883 currentSslStartDateTextView.text = currentSslStartDateStringBuilder
884 currentSslEndDateTextView.text = currentSslEndDateStringBuilder
887 // Set the initial display status of the SSL certificates card views.
888 if (pinnedSslCertificateSwitch.isChecked) { // An SSL certificate is pinned.
889 // Set the visibility of the saved SSL certificate.
890 if (savedSslIssuedToCNameString == null)
891 savedSslCardView.visibility = View.GONE
893 savedSslCardView.visibility = View.VISIBLE
895 // Set the visibility of the current website SSL certificate.
896 if (DomainsActivity.sslIssuedToCName == null) { // There is no current SSL certificate.
897 // Hide the SSL certificate.
898 currentSslCardView.visibility = View.GONE
900 // Show the instruction.
901 noCurrentWebsiteCertificateTextView.visibility = View.VISIBLE
902 } else { // There is a current SSL certificate.
903 // Show the SSL certificate.
904 currentSslCardView.visibility = View.VISIBLE
906 // Hide the instruction.
907 noCurrentWebsiteCertificateTextView.visibility = View.GONE
910 // Set the status of the radio buttons and the card view backgrounds.
911 if (savedSslCardView.visibility == View.VISIBLE) { // The saved SSL certificate is displayed.
912 // Check the saved SSL certificate radio button.
913 savedSslCertificateRadioButton.isChecked = true
915 // Uncheck the current website SSL certificate radio button.
916 currentWebsiteCertificateRadioButton.isChecked = false
918 // Darken the background of the current website SSL certificate linear layout.
919 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.translucent_background)
920 } else if (currentSslCardView.visibility == View.VISIBLE) { // The saved SSL certificate is hidden but the current website SSL certificate is visible.
921 // Check the current website SSL certificate radio button.
922 currentWebsiteCertificateRadioButton.isChecked = true
924 // Uncheck the saved SSL certificate radio button.
925 savedSslCertificateRadioButton.isChecked = false
926 } else { // Neither SSL certificate is visible.
927 // Uncheck both radio buttons.
928 savedSslCertificateRadioButton.isChecked = false
929 currentWebsiteCertificateRadioButton.isChecked = false
931 } else { // An SSL certificate is not pinned.
932 // Hide the SSl certificates and instructions.
933 savedSslCardView.visibility = View.GONE
934 currentSslCardView.visibility = View.GONE
935 noCurrentWebsiteCertificateTextView.visibility = View.GONE
937 // Uncheck the radio buttons.
938 savedSslCertificateRadioButton.isChecked = false
939 currentWebsiteCertificateRadioButton.isChecked = false
942 // Populate the saved and current IP addresses.
943 savedIpAddressesTextView.text = savedIpAddresses
944 currentIpAddressesTextView.text = DomainsActivity.currentIpAddresses
946 // Set the initial display status of the IP addresses card views.
947 if (pinnedIpAddressesSwitch.isChecked) { // IP addresses are pinned.
948 // Set the visibility of the saved IP addresses.
949 if (savedIpAddresses == null) // There are no saved IP addresses.
950 savedIpAddressesCardView.visibility = View.GONE
951 else // There are saved IP addresses.
952 savedIpAddressesCardView.visibility = View.VISIBLE
954 // Set the visibility of the current IP addresses.
955 currentIpAddressesCardView.visibility = View.VISIBLE
957 // Set the status of the radio buttons and the card view backgrounds.
958 if (savedIpAddressesCardView.visibility == View.VISIBLE) { // The saved IP addresses are displayed.
959 // Check the saved IP addresses radio button.
960 savedIpAddressesRadioButton.isChecked = true
962 // Uncheck the current IP addresses radio button.
963 currentIpAddressesRadioButton.isChecked = false
965 // Darken the background of the current IP addresses linear layout.
966 currentIpAddressesLinearLayout.setBackgroundResource(R.color.translucent_background)
967 } else { // The saved IP addresses are hidden.
968 // Check the current IP addresses radio button.
969 currentIpAddressesRadioButton.isChecked = true
971 // Uncheck the saved IP addresses radio button.
972 savedIpAddressesRadioButton.isChecked = false
974 } else { // IP addresses are not pinned.
975 // Hide the IP addresses card views.
976 savedIpAddressesCardView.visibility = View.GONE
977 currentIpAddressesCardView.visibility = View.GONE
979 // Uncheck the radio buttons.
980 savedIpAddressesRadioButton.isChecked = false
981 currentIpAddressesRadioButton.isChecked = false
985 // Set the JavaScript spinner listener.
986 javaScriptSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
987 override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
991 if (javaScriptDefault)
992 javaScriptImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.javascript_enabled, null))
994 javaScriptImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.privacy_mode, null))
996 // Show the text view.
997 javaScriptTextView.visibility = View.VISIBLE
999 // Set the background color to be transparent.
1000 javaScriptLinearLayout.setBackgroundColor(getColor(context, R.color.transparent))
1005 javaScriptImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.javascript_enabled, null))
1007 // Hide the text view.
1008 javaScriptTextView.visibility = View.GONE
1010 // Set the background color to be blue.
1011 javaScriptLinearLayout.setBackgroundColor(getColor(context, R.color.blue_background))
1016 javaScriptImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.privacy_mode, null))
1018 // Hide the text view.
1019 javaScriptTextView.visibility = View.GONE
1021 // Set the background color to be blue.
1022 javaScriptLinearLayout.setBackgroundColor(getColor(context, R.color.blue_background))
1026 // Calculate if JavaScript is enabled, either because it is the system default and that default is enabled, or because it is explicitly set to be enabled for this domain.
1027 val updatedJavaScriptEnabled = (((position == 0) && javaScriptDefault) || (position == 1))
1029 // Set the DOM storage spinner and text view status based on the JavaScript status.
1030 domStorageSpinner.isEnabled = updatedJavaScriptEnabled
1031 domStorageTextView.isEnabled = updatedJavaScriptEnabled
1033 // Set the DOM storage icon ghosted status based on the JavaScript status.
1034 domStorageImageView.isEnabled = updatedJavaScriptEnabled
1037 override fun onNothingSelected(parent: AdapterView<*>?) {
1042 // Set the cookies switch listener.
1043 cookiesSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
1044 override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
1045 // Update the icon and the text view settings.
1046 setIconAndTextViewSettings(position, cookiesDefault, cookiesLinearLayout, cookiesImageView, cookiesTextView)
1049 override fun onNothingSelected(parent: AdapterView<*>?) {
1054 // Set the DOM Storage spinner listener.
1055 domStorageSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
1056 override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
1057 // Update the icon and the text view settings.
1058 setIconAndTextViewSettings(position, domStorageDefault, domStorageLinearLayout, domStorageImageView, domStorageTextView)
1061 override fun onNothingSelected(parent: AdapterView<*>?) {
1066 // Set the form data spinner listener. It can be removed once the minimum API >= 26.
1067 if (Build.VERSION.SDK_INT < 26) {
1068 formDataSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
1069 override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
1070 // Update the icon and the text view settings.
1071 setIconAndTextViewSettings(position, formDataDefault, formDataLinearLayout, formDataImageView, formDataTextView)
1074 override fun onNothingSelected(parent: AdapterView<*>?) {
1080 // Set the EasyList spinner listener.
1081 easyListSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
1082 override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
1083 // Update the icon and the text view settings.
1084 setIconAndTextViewSettings(position, easyListDefault, easyListLinearLayout, easyListImageView, easyListTextView)
1087 override fun onNothingSelected(parent: AdapterView<*>?) {
1092 // Set the EasyPrivacy spinner listener.
1093 easyPrivacySpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
1094 override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
1095 // Update the icon and the text view settings.
1096 setIconAndTextViewSettings(position, easyPrivacyDefault, easyPrivacyLinearLayout, easyPrivacyImageView, easyPrivacyTextView)
1099 override fun onNothingSelected(parent: AdapterView<*>?) {
1104 // Set the Fanboy's Annoyance List spinner listener.
1105 fanboysAnnoyanceListSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
1106 override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
1107 // Update the icon and the text view settings.
1108 setIconAndTextViewSettings(position, fanboysAnnoyanceListDefault, fanboysAnnoyanceListLinearLayout, fanboysAnnoyanceListImageView, fanboysAnnoyanceListTextView)
1110 // Calculate if Fanboy's Annoyance List is enabled, either because it is the system default and that default is enabled, or because it is explicitly set to be enabled for this domain.
1111 val updatedFanboysAnnoyanceListEnabled = (((position == 0) && fanboysAnnoyanceListDefault) || (position == 1))
1113 // Set Fanboy's Social Blocking List spinner and test view status based on the Annoyance List status.
1114 fanboysSocialBlockingListSpinner.isEnabled = !updatedFanboysAnnoyanceListEnabled
1115 fanboysSocialBlockingListTextView.isEnabled = !updatedFanboysAnnoyanceListEnabled
1117 // Set the Social Blocking List icon ghosted status based on the Annoyance List status.
1118 fanboysSocialBlockingListImageView.isEnabled = !updatedFanboysAnnoyanceListEnabled
1121 override fun onNothingSelected(parent: AdapterView<*>?) {
1126 // Set the Fanboy's Social Blocking List spinner listener.
1127 fanboysSocialBlockingListSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
1128 override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
1129 // Update the icon and the text view settings.
1130 setIconAndTextViewSettings(position, fanboysSocialBlockingListDefault, fanboysSocialBlockingListLinearLayout, fanboysSocialBlockingListImageView, fanboysSocialBlockingListTextView)
1133 override fun onNothingSelected(parent: AdapterView<*>?) {
1138 // Set the UltraList spinner listener.
1139 ultraListSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
1140 override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
1141 // Update the icon and the text view settings.
1142 setIconAndTextViewSettings(position, ultraListDefault, ultraListLinearLayout, ultraListImageView, ultraListTextView)
1145 override fun onNothingSelected(parent: AdapterView<*>?) {
1150 // Set the UltraPrivacy spinner listener.
1151 ultraPrivacySpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
1152 override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
1153 // Update the icon and the text view settings.
1154 setIconAndTextViewSettings(position, ultraPrivacyDefault, ultraPrivacyLinearLayout, ultraPrivacyImageView, ultraPrivacyTextView)
1157 override fun onNothingSelected(parent: AdapterView<*>?) {
1162 // Set the block all third-party requests spinner listener.
1163 blockAllThirdPartyRequestsSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
1164 override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
1165 // Update the icon and the text view settings.
1166 setIconAndTextViewSettings(position, blockAllThirdPartyRequestsDefault, blockAllThirdPartyRequestsLinearLayout, blockAllThirdPartyRequestsImageView, blockAllThirdPartyRequestsTextView)
1169 override fun onNothingSelected(parent: AdapterView<*>?) {
1174 // Set the user agent spinner listener.
1175 userAgentSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
1176 override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
1177 // Set the new user agent.
1179 DOMAINS_SYSTEM_DEFAULT_USER_AGENT -> {
1180 // Show the user agent text view.
1181 userAgentTextView.visibility = View.VISIBLE
1183 // Hide the custom user agent edit text.
1184 customUserAgentEditText.visibility = View.GONE
1186 // Set the user text.
1187 when (defaultUserAgentArrayPosition) {
1188 // This is probably because it was set in an older version of Privacy Browser before the switch to persistent user agent names.
1189 UNRECOGNIZED_USER_AGENT -> userAgentTextView.text = userAgentDefault
1191 // Display the `WebView` default user agent.
1192 SETTINGS_WEBVIEW_DEFAULT_USER_AGENT -> userAgentTextView.text = webViewDefaultUserAgentString
1194 // Display the custom user agent.
1195 SETTINGS_CUSTOM_USER_AGENT -> userAgentTextView.text = customUserAgentStringDefault
1197 // Get the user agent string from the user agent data array.
1198 else -> userAgentTextView.text = userAgentDataArray[defaultUserAgentArrayPosition]
1201 // Set the background color to be transparent.
1202 userAgentLinearLayout.setBackgroundColor(getColor(context, R.color.transparent))
1205 DOMAINS_WEBVIEW_DEFAULT_USER_AGENT -> {
1206 // Show the user agent text view.
1207 userAgentTextView.visibility = View.VISIBLE
1209 // Set the user agent text.
1210 userAgentTextView.text = webViewDefaultUserAgentString
1212 // Hide the custom user agent edit text.
1213 customUserAgentEditText.visibility = View.GONE
1215 // Set the background color to be blue.
1216 userAgentLinearLayout.setBackgroundColor(getColor(context, R.color.blue_background))
1219 DOMAINS_CUSTOM_USER_AGENT -> {
1220 // Hide the user agent text view.
1221 userAgentTextView.visibility = View.GONE
1223 // Show the custom user agent edit text.
1224 customUserAgentEditText.visibility = View.VISIBLE
1226 // Set the current user agent name as the text.
1227 customUserAgentEditText.setText(currentUserAgentName)
1229 // Set the background color to be blue.
1230 userAgentLinearLayout.setBackgroundColor(getColor(context, R.color.blue_background))
1234 // Show the user agent text view.
1235 userAgentTextView.visibility = View.VISIBLE
1237 // Set the text from the user agent data array, which has one less entry than the spinner, so the position must be decremented.
1238 userAgentTextView.text = userAgentDataArray[position - 1]
1240 // Hide the custom user agent edit text.
1241 customUserAgentEditText.visibility = View.GONE
1243 // Set the background color to be blue.
1244 userAgentLinearLayout.setBackgroundColor(getColor(context, R.color.blue_background))
1249 override fun onNothingSelected(parent: AdapterView<*>?) {
1254 // Set the font size spinner listener.
1255 fontSizeSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
1256 override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
1257 // Update the font size display options.
1258 if (position == SYSTEM_DEFAULT) { // The system default font size has been selected.
1259 // Show the default font size text view.
1260 defaultFontSizeTextView.visibility = View.VISIBLE
1262 // Hide the custom font size edit text.
1263 customFontSizeEditText.visibility = View.GONE
1265 // Set the background color to be transparent.
1266 fontSizeLinearLayout.setBackgroundColor(getColor(context, R.color.transparent))
1267 } else { // A custom font size has been selected.
1268 // Hide the default font size text view.
1269 defaultFontSizeTextView.visibility = View.GONE
1271 // Show the custom font size edit text.
1272 customFontSizeEditText.visibility = View.VISIBLE
1274 // Set the background color to be blue.
1275 fontSizeLinearLayout.setBackgroundColor(getColor(context, R.color.blue_background))
1279 override fun onNothingSelected(parent: AdapterView<*>?) {
1284 // Set the swipe-to-refresh spinner listener.
1285 swipeToRefreshSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
1286 override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
1287 // Update the icon and the text view settings.
1288 setIconAndTextViewSettings(position, swipeToRefreshDefault, swipeToRefreshLinearLayout, swipeToRefreshImageView, swipeToRefreshTextView)
1291 override fun onNothingSelected(parent: AdapterView<*>?) {
1296 // Set the WebView theme spinner listener.
1297 webViewThemeSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
1298 override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
1299 // Update the icon and the WebView theme text view settings.
1302 // Set the icon color.
1303 when (appWebViewThemeEntryNumber) {
1304 SYSTEM_DEFAULT -> webViewThemeImageView.isSelected = (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO)
1305 LIGHT_THEME -> webViewThemeImageView.isSelected = true
1306 DARK_THEME -> webViewThemeImageView.isSelected = false
1309 // Show the WebView theme text view.
1310 webViewThemeTextView.visibility = View.VISIBLE
1312 // Set the background color to be transparent.
1313 webViewThemeLinearLayout.setBackgroundColor(getColor(context, R.color.transparent))
1317 // Set the icon color.
1318 webViewThemeImageView.isSelected = true
1320 // Hide the WebView theme text view.
1321 webViewThemeTextView.visibility = View.GONE
1323 // Set the background color to be blue.
1324 webViewThemeLinearLayout.setBackgroundColor(getColor(context, R.color.blue_background))
1328 // Set the icon color.
1329 webViewThemeImageView.isSelected = false
1331 // Hide the WebView theme text view.
1332 webViewThemeTextView.visibility = View.GONE
1334 // Set the background color to be blue.
1335 webViewThemeLinearLayout.setBackgroundColor(getColor(context, R.color.blue_background))
1340 override fun onNothingSelected(parent: AdapterView<*>?) {
1345 // Set the wide viewport spinner listener.
1346 wideViewportSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
1347 override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
1348 // Update the icon and the text view settings.
1349 setIconAndTextViewSettings(position, wideViewportDefault, wideViewportLinearLayout, wideViewportImageView, wideViewportTextView)
1352 override fun onNothingSelected(parent: AdapterView<*>?) {
1357 // Set the display webpage images spinner listener.
1358 displayImagesSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
1359 override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
1360 // Update the icon and the text view settings.
1361 setIconAndTextViewSettings(position, displayWebpageImagesDefault, displayImagesLinearLayout, displayImagesImageView, displayImagesTextView)
1364 override fun onNothingSelected(parent: AdapterView<*>?) {
1369 // Set the pinned SSL certificate switch listener.
1370 pinnedSslCertificateSwitch.setOnCheckedChangeListener { _: CompoundButton?, isChecked: Boolean ->
1371 // Update the icon color.
1372 pinnedSslCertificateImageView.isSelected = isChecked
1374 // Update the views.
1375 if (isChecked) { // SSL certificate pinning is enabled.
1376 // Update the visibility of the saved SSL certificate.
1377 if (savedSslIssuedToCNameString == null)
1378 savedSslCardView.visibility = View.GONE
1380 savedSslCardView.visibility = View.VISIBLE
1382 // Update the visibility of the current website SSL certificate.
1383 if (DomainsActivity.sslIssuedToCName == null) {
1384 // Hide the SSL certificate.
1385 currentSslCardView.visibility = View.GONE
1387 // Show the instruction.
1388 noCurrentWebsiteCertificateTextView.visibility = View.VISIBLE
1390 // Show the SSL certificate.
1391 currentSslCardView.visibility = View.VISIBLE
1393 // Hide the instruction.
1394 noCurrentWebsiteCertificateTextView.visibility = View.GONE
1397 // Set the status of the radio buttons.
1398 if (savedSslCardView.visibility == View.VISIBLE) { // The saved SSL certificate is displayed.
1399 // Check the saved SSL certificate radio button.
1400 savedSslCertificateRadioButton.isChecked = true
1402 // Uncheck the current website SSL certificate radio button.
1403 currentWebsiteCertificateRadioButton.isChecked = false
1405 // Set the background of the saved SSL certificate linear layout to be transparent.
1406 savedSslCertificateLinearLayout.setBackgroundResource(R.color.transparent)
1408 // Darken the background of the current website SSL certificate linear layout according to the theme.
1409 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.translucent_background)
1411 // Scroll to the current website SSL certificate card.
1412 savedSslCardView.parent.requestChildFocus(savedSslCardView, savedSslCardView)
1413 } else if (currentSslCardView.visibility == View.VISIBLE) { // The saved SSL certificate is hidden but the current website SSL certificate is visible.
1414 // Check the current website SSL certificate radio button.
1415 currentWebsiteCertificateRadioButton.isChecked = true
1417 // Uncheck the saved SSL certificate radio button.
1418 savedSslCertificateRadioButton.isChecked = false
1420 // Set the background of the current website SSL certificate linear layout to be transparent.
1421 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.transparent)
1423 // Darken the background of the saved SSL certificate linear layout according to the theme.
1424 savedSslCertificateLinearLayout.setBackgroundResource(R.color.translucent_background)
1426 // Scroll to the current website SSL certificate card.
1427 currentSslCardView.parent.requestChildFocus(currentSslCardView, currentSslCardView)
1428 } else { // Neither SSL certificate is visible.
1429 // Uncheck both radio buttons.
1430 savedSslCertificateRadioButton.isChecked = false
1431 currentWebsiteCertificateRadioButton.isChecked = false
1433 // Scroll to the current website SSL certificate card.
1434 noCurrentWebsiteCertificateTextView.parent.requestChildFocus(noCurrentWebsiteCertificateTextView, noCurrentWebsiteCertificateTextView)
1436 } else { // SSL certificate pinning is disabled.
1437 // Hide the SSl certificates and instructions.
1438 savedSslCardView.visibility = View.GONE
1439 currentSslCardView.visibility = View.GONE
1440 noCurrentWebsiteCertificateTextView.visibility = View.GONE
1442 // Uncheck the radio buttons.
1443 savedSslCertificateRadioButton.isChecked = false
1444 currentWebsiteCertificateRadioButton.isChecked = false
1448 // Set the saved SSL card view listener.
1449 savedSslCardView.setOnClickListener {
1450 // Check the saved SSL certificate radio button.
1451 savedSslCertificateRadioButton.isChecked = true
1453 // Uncheck the current website SSL certificate radio button.
1454 currentWebsiteCertificateRadioButton.isChecked = false
1456 // Set the background of the saved SSL certificate linear layout to be transparent.
1457 savedSslCertificateLinearLayout.setBackgroundResource(R.color.transparent)
1459 // Darken the background of the current website SSL certificate linear layout.
1460 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.translucent_background)
1463 // Set the saved SSL certificate radio button listener.
1464 savedSslCertificateRadioButton.setOnClickListener {
1465 // Check the saved SSL certificate radio button.
1466 savedSslCertificateRadioButton.isChecked = true
1468 // Uncheck the current website SSL certificate radio button.
1469 currentWebsiteCertificateRadioButton.isChecked = false
1471 // Set the background of the saved SSL certificate linear layout to be transparent.
1472 savedSslCertificateLinearLayout.setBackgroundResource(R.color.transparent)
1474 // Darken the background of the current website SSL certificate linear layout.
1475 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.translucent_background)
1478 // Set the current SSL card view listener.
1479 currentSslCardView.setOnClickListener {
1480 // Check the current website SSL certificate radio button.
1481 currentWebsiteCertificateRadioButton.isChecked = true
1483 // Uncheck the saved SSL certificate radio button.
1484 savedSslCertificateRadioButton.isChecked = false
1486 // Set the background of the current website SSL certificate linear layout to be transparent.
1487 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.transparent)
1489 // Darken the background of the saved SSL certificate linear layout.
1490 savedSslCertificateLinearLayout.setBackgroundResource(R.color.translucent_background)
1493 // Set the current website certificate radio button listener.
1494 currentWebsiteCertificateRadioButton.setOnClickListener {
1495 // Check the current website SSL certificate radio button.
1496 currentWebsiteCertificateRadioButton.isChecked = true
1498 // Uncheck the saved SSL certificate radio button.
1499 savedSslCertificateRadioButton.isChecked = false
1501 // Set the background of the current website SSL certificate linear layout to be transparent.
1502 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.transparent)
1504 // Darken the background of the saved SSL certificate linear layout.
1505 savedSslCertificateLinearLayout.setBackgroundResource(R.color.translucent_background)
1508 // Set the pinned IP addresses switch listener.
1509 pinnedIpAddressesSwitch.setOnCheckedChangeListener { _: CompoundButton?, isChecked: Boolean ->
1510 // Update the icon color.
1511 pinnedIpAddressesImageView.isSelected = isChecked
1513 // Update the views.
1514 if (isChecked) { // IP addresses pinning is enabled.
1515 // Update the visibility of the saved IP addresses card view.
1516 if (savedIpAddresses == null)
1517 savedIpAddressesCardView.visibility = View.GONE
1519 savedIpAddressesCardView.visibility = View.VISIBLE
1521 // Show the current IP addresses card view.
1522 currentIpAddressesCardView.visibility = View.VISIBLE
1524 // Set the status of the radio buttons.
1525 if (savedIpAddressesCardView.visibility == View.VISIBLE) { // The saved IP addresses are visible.
1526 // Check the saved IP addresses radio button.
1527 savedIpAddressesRadioButton.isChecked = true
1529 // Uncheck the current IP addresses radio button.
1530 currentIpAddressesRadioButton.isChecked = false
1532 // Set the background of the saved IP addresses linear layout to be transparent.
1533 savedSslCertificateLinearLayout.setBackgroundResource(R.color.transparent)
1535 // Darken the background of the current IP addresses linear layout.
1536 currentIpAddressesLinearLayout.setBackgroundResource(R.color.translucent_background)
1537 } else { // The saved IP addresses are not visible.
1538 // Check the current IP addresses radio button.
1539 currentIpAddressesRadioButton.isChecked = true
1541 // Uncheck the saved IP addresses radio button.
1542 savedIpAddressesRadioButton.isChecked = false
1544 // Set the background of the current IP addresses linear layout to be transparent.
1545 currentIpAddressesLinearLayout.setBackgroundResource(R.color.transparent)
1547 // Darken the background of the saved IP addresses linear layout.
1548 savedIpAddressesLinearLayout.setBackgroundResource(R.color.translucent_background)
1551 // Scroll to the bottom of the card views.
1552 currentIpAddressesCardView.parent.requestChildFocus(currentIpAddressesCardView, currentIpAddressesCardView)
1553 } else { // IP addresses pinning is disabled.
1554 // Hide the IP addresses card views.
1555 savedIpAddressesCardView.visibility = View.GONE
1556 currentIpAddressesCardView.visibility = View.GONE
1558 // Uncheck the radio buttons.
1559 savedIpAddressesRadioButton.isChecked = false
1560 currentIpAddressesRadioButton.isChecked = false
1564 // Set the saved IP addresses card view listener.
1565 savedIpAddressesCardView.setOnClickListener {
1566 // Check the saved IP addresses radio button.
1567 savedIpAddressesRadioButton.isChecked = true
1569 // Uncheck the current website IP addresses radio button.
1570 currentIpAddressesRadioButton.isChecked = false
1572 // Set the background of the saved IP addresses linear layout to be transparent.
1573 savedIpAddressesLinearLayout.setBackgroundResource(R.color.transparent)
1575 // Darken the background of the current IP addresses linear layout.
1576 currentIpAddressesLinearLayout.setBackgroundResource(R.color.translucent_background)
1579 // Set the saved IP addresses radio button listener.
1580 savedIpAddressesRadioButton.setOnClickListener {
1581 // Check the saved IP addresses radio button.
1582 savedIpAddressesRadioButton.isChecked = true
1584 // Uncheck the current website IP addresses radio button.
1585 currentIpAddressesRadioButton.isChecked = false
1587 // Set the background of the saved IP addresses linear layout to be transparent.
1588 savedIpAddressesLinearLayout.setBackgroundResource(R.color.transparent)
1590 // Darken the background of the current IP addresses linear layout.
1591 currentIpAddressesLinearLayout.setBackgroundResource(R.color.translucent_background)
1594 // Set the current IP addresses card view listener.
1595 currentIpAddressesCardView.setOnClickListener {
1596 // Check the current IP addresses radio button.
1597 currentIpAddressesRadioButton.isChecked = true
1599 // Uncheck the saved IP addresses radio button.
1600 savedIpAddressesRadioButton.isChecked = false
1602 // Set the background of the current IP addresses linear layout to be transparent.
1603 currentIpAddressesLinearLayout.setBackgroundResource(R.color.transparent)
1605 // Darken the background of the saved IP addresses linear layout.
1606 savedIpAddressesLinearLayout.setBackgroundResource(R.color.translucent_background)
1609 // Set the current IP addresses radio button listener.
1610 currentIpAddressesRadioButton.setOnClickListener {
1611 // Check the current IP addresses radio button.
1612 currentIpAddressesRadioButton.isChecked = true
1614 // Uncheck the saved IP addresses radio button.
1615 savedIpAddressesRadioButton.isChecked = false
1617 // Set the background of the current IP addresses linear layout to be transparent.
1618 currentIpAddressesLinearLayout.setBackgroundResource(R.color.transparent)
1620 // Darken the background of the saved IP addresses linear layout.
1621 savedIpAddressesLinearLayout.setBackgroundResource(R.color.translucent_background)
1624 // Set the scroll Y.
1625 domainSettingsScrollView.post { domainSettingsScrollView.scrollY = scrollY }
1627 // Return the domain settings view.
1628 return domainSettingsView
1631 private fun checkDomainNameAgainstCertificate(domainName: String?, certificateCommonName: String?): Boolean {
1632 // Initialize the domain names match tracker.
1633 var domainNamesMatch = false
1635 // Check various wildcard permutations if the domain name and the certificate Common Name are not empty.
1636 if ((domainName != null) && (certificateCommonName != null)) {
1637 // Check if the domains match.
1638 if (domainName == certificateCommonName)
1639 domainNamesMatch = true
1641 // If the domain name starts with a wildcard, check the base domain against all the subdomains of the certificate Common Name.
1642 if (!domainNamesMatch && domainName.startsWith("*.") && domainName.length > 2) {
1643 // Remove the initial `*.`.
1644 val baseDomainName = domainName.substring(2)
1646 // Create a copy of the certificate Common Name to test subdomains.
1647 var certificateCommonNameSubdomain: String = certificateCommonName
1649 // Check all the subdomains in the certificate Common Name subdomain against the base domain name.
1650 while (!domainNamesMatch && certificateCommonNameSubdomain.contains(".")) { // Stop checking if the domain names match or if there are no more dots.
1651 // Test the certificate Common Name subdomain against the base domain name.
1652 if (certificateCommonNameSubdomain == baseDomainName)
1653 domainNamesMatch = true
1655 // Strip out the lowest subdomain of the certificate Common Name subdomain.
1656 certificateCommonNameSubdomain = try {
1657 certificateCommonNameSubdomain.substring(certificateCommonNameSubdomain.indexOf(".") + 1)
1658 } catch (e: IndexOutOfBoundsException) { // The certificate Common Name subdomain ends with a dot.
1664 // If the certificate Common Name starts with a wildcard, check the base common name against all the subdomains of the domain name.
1665 if (!domainNamesMatch && certificateCommonName.startsWith("*.") && certificateCommonName.length > 2) {
1666 // Remove the initial `*.`.
1667 val baseCertificateCommonName = certificateCommonName.substring(2)
1669 // Setup a copy of domain name to test subdomains.
1670 var domainNameSubdomain: String = domainName
1672 // Check all the subdomains in the domain name subdomain against the base certificate Common Name.
1673 while (!domainNamesMatch && domainNameSubdomain.contains(".") && domainNameSubdomain.length > 2) {
1674 // Test the domain name subdomain against the base certificate Common Name.
1675 if (domainNameSubdomain == baseCertificateCommonName)
1676 domainNamesMatch = true
1678 // Strip out the lowest subdomain of the domain name subdomain.
1679 domainNameSubdomain = try {
1680 domainNameSubdomain.substring(domainNameSubdomain.indexOf(".") + 1)
1681 } catch (e: IndexOutOfBoundsException) { // `domainNameSubdomain` ends with a dot.
1687 // If both names start with a wildcard, check if the root of one contains the root of the other.
1688 if (!domainNamesMatch && domainName.startsWith("*.") && domainName.length > 2 && certificateCommonName.startsWith("*.") && certificateCommonName.length > 2) {
1689 // Remove the wildcards.
1690 val rootDomainName = domainName.substring(2)
1691 val rootCertificateCommonName = certificateCommonName.substring(2)
1693 // Check if one name ends with the contents of the other. If so, there will be overlap in the their wildcard subdomains.
1694 if (rootDomainName.endsWith(rootCertificateCommonName) || rootCertificateCommonName.endsWith(rootDomainName))
1695 domainNamesMatch = true
1699 return domainNamesMatch
1702 private fun populateTextView(defaultValue: Boolean, arrayAdapter: ArrayAdapter<CharSequence>, textView: TextView) {
1704 textView.text = if (defaultValue)
1705 arrayAdapter.getItem(ENABLED)
1707 arrayAdapter.getItem(DISABLED)
1710 private fun setIconAndTextViewSettings(databaseInt: Int, defaultValue: Boolean, linearLayout: LinearLayout, imageView: ImageView, textView: TextView) {
1711 // Set the icon and text view settings.
1712 when (databaseInt) {
1714 // Set the icon color.
1715 imageView.isSelected = defaultValue
1717 // Show the text view.
1718 textView.visibility = View.VISIBLE
1720 // Set the background color to be transparent.
1721 linearLayout.setBackgroundColor(getColor(context, R.color.transparent))
1725 // Set the icon color.
1726 imageView.isSelected = true
1728 // Hide the text view.
1729 textView.visibility = View.GONE
1731 // Set the background color to be blue.
1732 linearLayout.setBackgroundColor(getColor(context, R.color.blue_background))
1736 // Set the icon color.
1737 imageView.isSelected = false
1739 // Hide the text view.
1740 textView.visibility = View.GONE
1742 // Set the background color to be blue.
1743 linearLayout.setBackgroundColor(getColor(context, R.color.blue_background))