]> gitweb.stoutner.com Git - PrivacyBrowserAndroid.git/blob - app/src/main/java/com/stoutner/privacybrowser/fragments/DomainSettingsFragment.java
Create UltraList. https://redmine.stoutner.com/issues/450
[PrivacyBrowserAndroid.git] / app / src / main / java / com / stoutner / privacybrowser / fragments / DomainSettingsFragment.java
1 /*
2  * Copyright © 2017-2019 Soren Stoutner <soren@stoutner.com>.
3  *
4  * This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
5  *
6  * Privacy Browser is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * Privacy Browser is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with Privacy Browser.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 package com.stoutner.privacybrowser.fragments;
21
22 import android.annotation.SuppressLint;
23 import android.content.Context;
24 import android.content.SharedPreferences;
25 import android.content.res.Resources;
26 import android.database.Cursor;
27 import android.os.Build;
28 import android.os.Bundle;
29 import android.preference.PreferenceManager;
30 import android.text.Editable;
31 import android.text.SpannableStringBuilder;
32 import android.text.Spanned;
33 import android.text.TextWatcher;
34 import android.text.style.ForegroundColorSpan;
35 import android.view.LayoutInflater;
36 import android.view.View;
37 import android.view.ViewGroup;
38 import android.webkit.WebView;
39 import android.widget.AdapterView;
40 import android.widget.ArrayAdapter;
41 import android.widget.CompoundButton;
42 import android.widget.EditText;
43 import android.widget.ImageView;
44 import android.widget.LinearLayout;
45 import android.widget.RadioButton;
46 import android.widget.Spinner;
47 import android.widget.Switch;
48 import android.widget.TextView;
49
50 import androidx.annotation.NonNull;
51 import androidx.cardview.widget.CardView;
52 import androidx.fragment.app.Fragment;  // The AndroidX fragment must be used until minimum API >= 23.  Otherwise `getContext()` does not work.
53
54 import com.stoutner.privacybrowser.R;
55 import com.stoutner.privacybrowser.activities.DomainsActivity;
56 import com.stoutner.privacybrowser.activities.MainWebViewActivity;
57 import com.stoutner.privacybrowser.helpers.DomainsDatabaseHelper;
58
59 import java.text.DateFormat;
60 import java.util.Calendar;
61 import java.util.Date;
62
63 public class DomainSettingsFragment extends Fragment {
64     // `DATABASE_ID` is used by activities calling this fragment.
65     public static final String DATABASE_ID = "database_id";
66
67     // `databaseId` is public static so it can be accessed from `DomainsActivity`. It is also used in `onCreate()` and `onCreateView()`.
68     public static int databaseId;
69
70     @Override
71     public void onCreate(Bundle savedInstanceState) {
72         // Run the default commands.
73         super.onCreate(savedInstanceState);
74
75         // Remove the lint warning that `getArguments` might be null.
76         assert getArguments() != null;
77
78         // Store the database id in `databaseId`.
79         databaseId = getArguments().getInt(DATABASE_ID);
80     }
81
82     // The deprecated `getDrawable()` must be used until the minimum API >= 21.
83     @Override
84     public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
85         // Inflate `domain_settings_fragment`.  `false` does not attach it to the root `container`.
86         View domainSettingsView = inflater.inflate(R.layout.domain_settings_fragment, container, false);
87
88         // Get a handle for the context and the resources.
89         Context context = getContext();
90         Resources resources = getResources();
91
92         // Remove the error below that the context might be null.
93         assert context != null;
94
95         // Get a handle for the shared preference.
96         SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
97
98         // Store the default settings.
99         String defaultUserAgentName = sharedPreferences.getString("user_agent", getString(R.string.user_agent_default_value));
100         String defaultCustomUserAgentString = sharedPreferences.getString("custom_user_agent", getString(R.string.custom_user_agent_default_value));
101         String defaultFontSizeString = sharedPreferences.getString("font_size", getString(R.string.font_size_default_value));
102         boolean defaultSwipeToRefresh = sharedPreferences.getBoolean("swipe_to_refresh", true);
103         boolean darkTheme = sharedPreferences.getBoolean("dark_theme", false);
104         boolean defaultNightMode = sharedPreferences.getBoolean("night_mode", false);
105         boolean defaultWideViewport = sharedPreferences.getBoolean("wide_viewport", true);
106         boolean defaultDisplayWebpageImages = sharedPreferences.getBoolean("display_webpage_images", true);
107
108         // Get handles for the views in the fragment.
109         EditText domainNameEditText = domainSettingsView.findViewById(R.id.domain_settings_name_edittext);
110         ImageView javaScriptImageView = domainSettingsView.findViewById(R.id.javascript_imageview);
111         Switch javaScriptSwitch = domainSettingsView.findViewById(R.id.javascript_switch);
112         ImageView firstPartyCookiesImageView = domainSettingsView.findViewById(R.id.first_party_cookies_imageview);
113         Switch firstPartyCookiesSwitch = domainSettingsView.findViewById(R.id.first_party_cookies_switch);
114         LinearLayout thirdPartyCookiesLinearLayout = domainSettingsView.findViewById(R.id.third_party_cookies_linearlayout);
115         ImageView thirdPartyCookiesImageView = domainSettingsView.findViewById(R.id.third_party_cookies_imageview);
116         Switch thirdPartyCookiesSwitch = domainSettingsView.findViewById(R.id.third_party_cookies_switch);
117         ImageView domStorageImageView = domainSettingsView.findViewById(R.id.dom_storage_imageview);
118         Switch domStorageSwitch = domainSettingsView.findViewById(R.id.dom_storage_switch);
119         ImageView formDataImageView = domainSettingsView.findViewById(R.id.form_data_imageview);  // The form data views can be remove once the minimum API >= 26.
120         Switch formDataSwitch = domainSettingsView.findViewById(R.id.form_data_switch);  // The form data views can be remove once the minimum API >= 26.
121         ImageView easyListImageView = domainSettingsView.findViewById(R.id.easylist_imageview);
122         Switch easyListSwitch = domainSettingsView.findViewById(R.id.easylist_switch);
123         ImageView easyPrivacyImageView = domainSettingsView.findViewById(R.id.easyprivacy_imageview);
124         Switch easyPrivacySwitch = domainSettingsView.findViewById(R.id.easyprivacy_switch);
125         ImageView fanboysAnnoyanceListImageView = domainSettingsView.findViewById(R.id.fanboys_annoyance_list_imageview);
126         Switch fanboysAnnoyanceListSwitch = domainSettingsView.findViewById(R.id.fanboys_annoyance_list_switch);
127         ImageView fanboysSocialBlockingListImageView = domainSettingsView.findViewById(R.id.fanboys_social_blocking_list_imageview);
128         Switch fanboysSocialBlockingListSwitch = domainSettingsView.findViewById(R.id.fanboys_social_blocking_list_switch);
129         ImageView ultraListImageView = domainSettingsView.findViewById(R.id.ultralist_imageview);
130         Switch ultraListSwitch = domainSettingsView.findViewById(R.id.ultralist_switch);
131         ImageView ultraPrivacyImageView = domainSettingsView.findViewById(R.id.ultraprivacy_imageview);
132         Switch ultraPrivacySwitch = domainSettingsView.findViewById(R.id.ultraprivacy_switch);
133         ImageView blockAllThirdPartyRequestsImageView = domainSettingsView.findViewById(R.id.block_all_third_party_requests_imageview);
134         Switch blockAllThirdPartyRequestsSwitch = domainSettingsView.findViewById(R.id.block_all_third_party_requests_switch);
135         Spinner userAgentSpinner = domainSettingsView.findViewById(R.id.user_agent_spinner);
136         TextView userAgentTextView = domainSettingsView.findViewById(R.id.user_agent_textview);
137         EditText customUserAgentEditText = domainSettingsView.findViewById(R.id.custom_user_agent_edittext);
138         Spinner fontSizeSpinner = domainSettingsView.findViewById(R.id.font_size_spinner);
139         TextView fontSizeTextView = domainSettingsView.findViewById(R.id.font_size_textview);
140         ImageView swipeToRefreshImageView = domainSettingsView.findViewById(R.id.swipe_to_refresh_imageview);
141         Spinner swipeToRefreshSpinner = domainSettingsView.findViewById(R.id.swipe_to_refresh_spinner);
142         TextView swipeToRefreshTextView = domainSettingsView.findViewById(R.id.swipe_to_refresh_textview);
143         ImageView nightModeImageView = domainSettingsView.findViewById(R.id.night_mode_imageview);
144         Spinner nightModeSpinner = domainSettingsView.findViewById(R.id.night_mode_spinner);
145         TextView nightModeTextView = domainSettingsView.findViewById(R.id.night_mode_textview);
146         ImageView wideViewportImageView = domainSettingsView.findViewById(R.id.wide_viewport_imageview);
147         Spinner wideViewportSpinner = domainSettingsView.findViewById(R.id.wide_viewport_spinner);
148         TextView wideViewportTextView = domainSettingsView.findViewById(R.id.wide_viewport_textview);
149         ImageView displayWebpageImagesImageView = domainSettingsView.findViewById(R.id.display_webpage_images_imageview);
150         Spinner displayWebpageImagesSpinner = domainSettingsView.findViewById(R.id.display_webpage_images_spinner);
151         TextView displayImagesTextView = domainSettingsView.findViewById(R.id.display_webpage_images_textview);
152         ImageView pinnedSslCertificateImageView = domainSettingsView.findViewById(R.id.pinned_ssl_certificate_imageview);
153         Switch pinnedSslCertificateSwitch = domainSettingsView.findViewById(R.id.pinned_ssl_certificate_switch);
154         CardView savedSslCardView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_cardview);
155         LinearLayout savedSslCertificateLinearLayout = domainSettingsView.findViewById(R.id.saved_ssl_certificate_linearlayout);
156         RadioButton savedSslCertificateRadioButton = domainSettingsView.findViewById(R.id.saved_ssl_certificate_radiobutton);
157         TextView savedSslIssuedToCNameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_to_cname);
158         TextView savedSslIssuedToONameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_to_oname);
159         TextView savedSslIssuedToUNameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_to_uname);
160         TextView savedSslIssuedByCNameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_by_cname);
161         TextView savedSslIssuedByONameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_by_oname);
162         TextView savedSslIssuedByUNameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_by_uname);
163         TextView savedSslStartDateTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_start_date);
164         TextView savedSslEndDateTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_end_date);
165         CardView currentSslCardView = domainSettingsView.findViewById(R.id.current_website_certificate_cardview);
166         LinearLayout currentWebsiteCertificateLinearLayout = domainSettingsView.findViewById(R.id.current_website_certificate_linearlayout);
167         RadioButton currentWebsiteCertificateRadioButton = domainSettingsView.findViewById(R.id.current_website_certificate_radiobutton);
168         TextView currentSslIssuedToCNameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_to_cname);
169         TextView currentSslIssuedToONameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_to_oname);
170         TextView currentSslIssuedToUNameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_to_uname);
171         TextView currentSslIssuedByCNameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_by_cname);
172         TextView currentSslIssuedByONameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_by_oname);
173         TextView currentSslIssuedByUNameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_by_uname);
174         TextView currentSslStartDateTextView = domainSettingsView.findViewById(R.id.current_website_certificate_start_date);
175         TextView currentSslEndDateTextView = domainSettingsView.findViewById(R.id.current_website_certificate_end_date);
176         TextView noCurrentWebsiteCertificateTextView = domainSettingsView.findViewById(R.id.no_current_website_certificate);
177         ImageView pinnedIpAddressesImageView = domainSettingsView.findViewById(R.id.pinned_ip_addresses_imageview);
178         Switch pinnedIpAddressesSwitch = domainSettingsView.findViewById(R.id.pinned_ip_addresses_switch);
179         CardView savedIpAddressesCardView = domainSettingsView.findViewById(R.id.saved_ip_addresses_cardview);
180         LinearLayout savedIpAddressesLinearLayout = domainSettingsView.findViewById(R.id.saved_ip_addresses_linearlayout);
181         RadioButton savedIpAddressesRadioButton = domainSettingsView.findViewById(R.id.saved_ip_addresses_radiobutton);
182         TextView savedIpAddressesTextView = domainSettingsView.findViewById(R.id.saved_ip_addresses_textview);
183         CardView currentIpAddressesCardView = domainSettingsView.findViewById(R.id.current_ip_addresses_cardview);
184         LinearLayout currentIpAddressesLinearLayout = domainSettingsView.findViewById(R.id.current_ip_addresses_linearlayout);
185         RadioButton currentIpAddressesRadioButton = domainSettingsView.findViewById(R.id.current_ip_addresses_radiobutton);
186         TextView currentIpAddressesTextView = domainSettingsView.findViewById(R.id.current_ip_addresses_textview);
187
188         // Setup the pinned labels.
189         String cNameLabel = getString(R.string.common_name) + "  ";
190         String oNameLabel = getString(R.string.organization) + "  ";
191         String uNameLabel = getString(R.string.organizational_unit) + "  ";
192         String startDateLabel = getString(R.string.start_date) + "  ";
193         String endDateLabel = getString(R.string.end_date) + "  ";
194
195         // Initialize the database handler.  The `0` specifies the database version, but that is ignored and set instead using a constant in `DomainsDatabaseHelper`.
196         DomainsDatabaseHelper domainsDatabaseHelper = new DomainsDatabaseHelper(context, null, null, 0);
197
198         // Get the database cursor for this ID and move it to the first row.
199         Cursor domainCursor = domainsDatabaseHelper.getCursorForId(databaseId);
200         domainCursor.moveToFirst();
201
202         // Save the cursor entries as variables.
203         String domainNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.DOMAIN_NAME));
204         int javaScriptInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_JAVASCRIPT));
205         int firstPartyCookiesInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FIRST_PARTY_COOKIES));
206         int thirdPartyCookiesInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_THIRD_PARTY_COOKIES));
207         int domStorageInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_DOM_STORAGE));
208         int formDataInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FORM_DATA));  // Form data can be remove once the minimum API >= 26.
209         int easyListInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_EASYLIST));
210         int easyPrivacyInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_EASYPRIVACY));
211         int fanboysAnnoyanceListInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FANBOYS_ANNOYANCE_LIST));
212         int fanboysSocialBlockingListInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FANBOYS_SOCIAL_BLOCKING_LIST));
213         int ultraListInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ULTRALIST));
214         int ultraPrivacyInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_ULTRAPRIVACY));
215         int blockAllThirdPartyRequestsInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.BLOCK_ALL_THIRD_PARTY_REQUESTS));
216         String currentUserAgentName = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.USER_AGENT));
217         int fontSizeInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.FONT_SIZE));
218         int swipeToRefreshInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.SWIPE_TO_REFRESH));
219         int nightModeInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.NIGHT_MODE));
220         int wideViewportInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.WIDE_VIEWPORT));
221         int displayImagesInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.DISPLAY_IMAGES));
222         int pinnedSslCertificateInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.PINNED_SSL_CERTIFICATE));
223         String savedSslIssuedToCNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_TO_COMMON_NAME));
224         String savedSslIssuedToONameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_TO_ORGANIZATION));
225         String savedSslIssuedToUNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_TO_ORGANIZATIONAL_UNIT));
226         String savedSslIssuedByCNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_BY_COMMON_NAME));
227         String savedSslIssuedByONameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_BY_ORGANIZATION));
228         String savedSslIssuedByUNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_BY_ORGANIZATIONAL_UNIT));
229         int pinnedIpAddressesInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.PINNED_IP_ADDRESSES));
230         String savedIpAddresses = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.IP_ADDRESSES));
231
232         // Initialize the saved SSL certificate date variables.
233         Date savedSslStartDate = null;
234         Date savedSslEndDate = null;
235
236         // Only get the saved SSL certificate dates from the cursor if they are not set to `0`.
237         if (domainCursor.getLong(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_START_DATE)) != 0) {
238             savedSslStartDate = new Date(domainCursor.getLong(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_START_DATE)));
239         }
240
241         if (domainCursor.getLong(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_END_DATE)) != 0) {
242             savedSslEndDate = new Date(domainCursor.getLong(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_END_DATE)));
243         }
244
245         // Create array adapters for the spinners.
246         ArrayAdapter<CharSequence> translatedUserAgentArrayAdapter = ArrayAdapter.createFromResource(context, R.array.translated_domain_settings_user_agent_names, R.layout.spinner_item);
247         ArrayAdapter<CharSequence> fontSizeArrayAdapter = ArrayAdapter.createFromResource(context, R.array.domain_settings_font_size_entries, R.layout.spinner_item);
248         ArrayAdapter<CharSequence> fontSizeEntryValuesArrayAdapter = ArrayAdapter.createFromResource(context, R.array.domain_settings_font_size_entry_values, R.layout.spinner_item);
249         ArrayAdapter<CharSequence> swipeToRefreshArrayAdapter = ArrayAdapter.createFromResource(context, R.array.swipe_to_refresh_array, R.layout.spinner_item);
250         ArrayAdapter<CharSequence> nightModeArrayAdapter = ArrayAdapter.createFromResource(context, R.array.night_mode_array, R.layout.spinner_item);
251         ArrayAdapter<CharSequence> wideViewportArrayAdapter = ArrayAdapter.createFromResource(context, R.array.wide_viewport_array, R.layout.spinner_item);
252         ArrayAdapter<CharSequence> displayImagesArrayAdapter = ArrayAdapter.createFromResource(context, R.array.display_webpage_images_array, R.layout.spinner_item);
253
254         // Set the drop down view resource on the spinners.
255         translatedUserAgentArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items);
256         fontSizeArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items);
257         swipeToRefreshArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items);
258         nightModeArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items);
259         wideViewportArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items);
260         displayImagesArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items);
261
262         // Set the array adapters for the spinners.
263         userAgentSpinner.setAdapter(translatedUserAgentArrayAdapter);
264         fontSizeSpinner.setAdapter(fontSizeArrayAdapter);
265         swipeToRefreshSpinner.setAdapter(swipeToRefreshArrayAdapter);
266         nightModeSpinner.setAdapter(nightModeArrayAdapter);
267         wideViewportSpinner.setAdapter(wideViewportArrayAdapter);
268         displayWebpageImagesSpinner.setAdapter(displayImagesArrayAdapter);
269
270         // Create a spannable string builder for each TextView that needs multiple colors of text.
271         SpannableStringBuilder savedSslIssuedToCNameStringBuilder = new SpannableStringBuilder(cNameLabel + savedSslIssuedToCNameString);
272         SpannableStringBuilder savedSslIssuedToONameStringBuilder = new SpannableStringBuilder(oNameLabel + savedSslIssuedToONameString);
273         SpannableStringBuilder savedSslIssuedToUNameStringBuilder = new SpannableStringBuilder(uNameLabel + savedSslIssuedToUNameString);
274         SpannableStringBuilder savedSslIssuedByCNameStringBuilder = new SpannableStringBuilder(cNameLabel + savedSslIssuedByCNameString);
275         SpannableStringBuilder savedSslIssuedByONameStringBuilder = new SpannableStringBuilder(oNameLabel + savedSslIssuedByONameString);
276         SpannableStringBuilder savedSslIssuedByUNameStringBuilder = new SpannableStringBuilder(uNameLabel + savedSslIssuedByUNameString);
277
278         // Initialize the spannable string builders for the saved SSL certificate dates.
279         SpannableStringBuilder savedSslStartDateStringBuilder;
280         SpannableStringBuilder savedSslEndDateStringBuilder;
281
282         // Leave the SSL certificate dates empty if they are `null`.
283         if (savedSslStartDate == null) {
284             savedSslStartDateStringBuilder = new SpannableStringBuilder(startDateLabel);
285         } else {
286             savedSslStartDateStringBuilder = new SpannableStringBuilder(startDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(savedSslStartDate));
287         }
288
289         if (savedSslEndDate == null) {
290             savedSslEndDateStringBuilder = new SpannableStringBuilder(endDateLabel);
291         } else {
292             savedSslEndDateStringBuilder = new SpannableStringBuilder(endDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(savedSslEndDate));
293         }
294
295         // Create a red foreground color span.  The deprecated `resources.getColor` must be used until the minimum API >= 23.
296         final ForegroundColorSpan redColorSpan = new ForegroundColorSpan(resources.getColor(R.color.red_a700));
297
298         // Create a blue foreground color span.
299         final ForegroundColorSpan blueColorSpan;
300
301         // Set the blue color span according to the theme.  The deprecated `resources.getColor` must be used until the minimum API >= 23.
302         if (darkTheme) {
303             blueColorSpan = new ForegroundColorSpan(resources.getColor(R.color.blue_400));
304         } else {
305             blueColorSpan = new ForegroundColorSpan(resources.getColor(R.color.blue_700));
306         }
307
308         // Set the domain name from the the database cursor.
309         domainNameEditText.setText(domainNameString);
310
311         // Update the certificates' `Common Name` color when the domain name text changes.
312         domainNameEditText.addTextChangedListener(new TextWatcher() {
313             @Override
314             public void beforeTextChanged(CharSequence s, int start, int count, int after) {
315                 // Do nothing.
316             }
317
318             @Override
319             public void onTextChanged(CharSequence s, int start, int before, int count) {
320                 // Do nothing.
321             }
322
323             @Override
324             public void afterTextChanged(Editable s) {
325                 // Get the new domain name.
326                 String newDomainName = domainNameEditText.getText().toString();
327
328                 // Check the saved SSL certificate against the new domain name.
329                 boolean savedSslMatchesNewDomainName = checkDomainNameAgainstCertificate(newDomainName, savedSslIssuedToCNameString);
330
331                 // Create a `SpannableStringBuilder` for the saved certificate `Common Name`.
332                 SpannableStringBuilder savedSslCNameStringBuilder = new SpannableStringBuilder(cNameLabel + savedSslIssuedToCNameString);
333
334                 // Format the saved certificate `Common Name` color.  `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
335                 if (savedSslMatchesNewDomainName) {
336                     savedSslCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), savedSslCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
337                 } else {
338                     savedSslCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), savedSslCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
339                 }
340
341                 // Update the saved SSL issued to CName text view.
342                 savedSslIssuedToCNameTextView.setText(savedSslCNameStringBuilder);
343
344                 // Update the current website certificate if it exists.
345                 if (DomainsActivity.sslIssuedToCName != null) {
346                     // Check the current website certificate against the new domain name.
347                     boolean currentSslMatchesNewDomainName = checkDomainNameAgainstCertificate(newDomainName, DomainsActivity.sslIssuedToCName);
348
349                     // Create a `SpannableStringBuilder` for the current website certificate `Common Name`.
350                     SpannableStringBuilder currentSslCNameStringBuilder = new SpannableStringBuilder(cNameLabel + DomainsActivity.sslIssuedToCName);
351
352                     // Format the current certificate `Common Name` color.  `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
353                     if (currentSslMatchesNewDomainName) {
354                         currentSslCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), currentSslCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
355                     } else {
356                         currentSslCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), currentSslCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
357                     }
358
359                     // Update the current SSL issued to CName text view.
360                     currentSslIssuedToCNameTextView.setText(currentSslCNameStringBuilder);
361                 }
362             }
363         });
364
365         // Create a boolean to track if night mode is enabled.
366         boolean nightModeEnabled = (nightModeInt == DomainsDatabaseHelper.ENABLED) || ((nightModeInt == DomainsDatabaseHelper.SYSTEM_DEFAULT) && defaultNightMode);
367
368         // Disable the JavaScript switch if night mode is enabled.
369         if (nightModeEnabled) {
370             javaScriptSwitch.setEnabled(false);
371         } else {
372             javaScriptSwitch.setEnabled(true);
373         }
374
375         // Set the JavaScript icon.
376         if ((javaScriptInt == 1) || nightModeEnabled) {
377             javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.javascript_enabled));
378         } else {
379             javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.privacy_mode));
380         }
381
382         // Set the JavaScript switch status.
383         if (javaScriptInt == 1) {  // JavaScript is enabled.
384             javaScriptSwitch.setChecked(true);
385         } else {  // JavaScript is disabled.
386             javaScriptSwitch.setChecked(false);
387         }
388
389         // Set the first-party cookies status.  Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
390         if (firstPartyCookiesInt == 1) {  // First-party cookies are enabled.
391             firstPartyCookiesSwitch.setChecked(true);
392             firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_enabled));
393         } else {  // First-party cookies are disabled.
394             firstPartyCookiesSwitch.setChecked(false);
395
396             // Set the icon according to the theme.
397             if (darkTheme) {
398                 firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_dark));
399             } else {
400                 firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_light));
401             }
402         }
403
404         // Only display third-party cookies if SDK_INT >= 21.
405         if (Build.VERSION.SDK_INT >= 21) {  // Third-party cookies can be configured for API >= 21.
406             // Only enable third-party-cookies if first-party cookies are enabled.
407             if (firstPartyCookiesInt == 1) {  // First-party cookies are enabled.
408                 // Set the third-party cookies status.  Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
409                 if (thirdPartyCookiesInt == 1) {  // Both first-party and third-party cookies are enabled.
410                     thirdPartyCookiesSwitch.setChecked(true);
411                     thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_warning));
412                 } else {  // First party cookies are enabled but third-party cookies are disabled.
413                     thirdPartyCookiesSwitch.setChecked(false);
414
415                     // Set the icon according to the theme.
416                     if (darkTheme) {
417                         thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_dark));
418                     } else {
419                         thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_light));
420                     }
421                 }
422             } else {  // First-party cookies are disabled.
423                 // Set the status of third-party cookies.
424                 if (thirdPartyCookiesInt == 1) {
425                     thirdPartyCookiesSwitch.setChecked(true);
426                 } else {
427                     thirdPartyCookiesSwitch.setChecked(false);
428                 }
429
430                 // Disable the third-party cookies switch.
431                 thirdPartyCookiesSwitch.setEnabled(false);
432
433                 // Set the icon according to the theme.
434                 if (darkTheme) {
435                     thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_ghosted_dark));
436                 } else {
437                     thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_ghosted_light));
438                 }
439             }
440         } else {  // Third-party cookies cannot be configured for API <= 21.
441             // Hide the LinearLayout for third-party cookies.
442             thirdPartyCookiesLinearLayout.setVisibility(View.GONE);
443         }
444
445         // Only enable DOM storage if JavaScript is enabled.
446         if ((javaScriptInt == 1) || nightModeEnabled) {  // JavaScript is enabled.
447             // Enable the DOM storage `Switch`.
448             domStorageSwitch.setEnabled(true);
449
450             // Set the DOM storage status.  Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
451             if (domStorageInt == 1) {  // Both JavaScript and DOM storage are enabled.
452                 domStorageSwitch.setChecked(true);
453                 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_enabled));
454             } else {  // JavaScript is enabled but DOM storage is disabled.
455                 // Set the DOM storage switch to off.
456                 domStorageSwitch.setChecked(false);
457
458                 // Set the icon according to the theme.
459                 if (darkTheme) {
460                     domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_dark));
461                 } else {
462                     domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_light));
463                 }
464             }
465         } else {  // JavaScript is disabled.
466             // Disable the DOM storage `Switch`.
467             domStorageSwitch.setEnabled(false);
468
469             // Set the checked status of DOM storage.
470             if (domStorageInt == 1) {  // DOM storage is enabled but JavaScript is disabled.
471                 domStorageSwitch.setChecked(true);
472             } else {  // Both JavaScript and DOM storage are disabled.
473                 domStorageSwitch.setChecked(false);
474             }
475
476             // Set the icon according to the theme.
477             if (darkTheme) {
478                 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_dark));
479             } else {
480                 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_light));
481             }
482         }
483
484         // Set the form data status.  Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.  Form data can be removed once the minimum API >= 26.
485         if (Build.VERSION.SDK_INT >= 26) {  // Form data no longer applies to newer versions of Android.
486             // Hide the form data switch.
487             formDataSwitch.setVisibility(View.GONE);
488         } else {  // Form data should be displayed because this is an older version of Android.
489             if (formDataInt == 1) {  // Form data is on.
490                 formDataSwitch.setChecked(true);
491                 formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_enabled));
492             } else {  // Form data is off.
493                 // Turn the form data switch to off.
494                 formDataSwitch.setChecked(false);
495
496                 // Set the icon according to the theme.
497                 if (darkTheme) {
498                     formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_disabled_dark));
499                 } else {
500                     formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_disabled_light));
501                 }
502             }
503         }
504
505         // Set the EasyList status.  Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
506         if (easyListInt == 1) {  // EasyList is on.
507             // Turn the switch on.
508             easyListSwitch.setChecked(true);
509
510             // Set the icon according to the theme.
511             if (darkTheme) {
512                 easyListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_enabled_dark));
513             } else {
514                 easyListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_enabled_light));
515             }
516         } else {  // EasyList is off.
517             // Turn the switch off.
518             easyListSwitch.setChecked(false);
519
520             // Set the icon according to the theme.
521             if (darkTheme) {
522                 easyListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_disabled_dark));
523             } else {
524                 easyListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_disabled_light));
525             }
526         }
527
528         // Set the EasyPrivacy status.  Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
529         if (easyPrivacyInt == 1) {  // EasyPrivacy is on.
530             // Turn the switch on.
531             easyPrivacySwitch.setChecked(true);
532
533             // Set the icon according to the theme.
534             if (darkTheme) {
535                 easyPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_enabled_dark));
536             } else {
537                 easyPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_enabled_light));
538             }
539         } else {  // EasyPrivacy is off.
540             // Turn the switch off.
541             easyPrivacySwitch.setChecked(false);
542
543             // Set the icon according to the theme.
544             if (darkTheme) {
545                 easyPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_disabled_dark));
546             } else {
547                 easyPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_disabled_light));
548             }
549         }
550
551         // Set the Fanboy's Annoyance List status.  Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
552         if (fanboysAnnoyanceListInt == 1) {  // Fanboy's Annoyance List is on.
553             // Turn the switch on.
554             fanboysAnnoyanceListSwitch.setChecked(true);
555
556             // Set the icon according to the theme.
557             if (darkTheme) {
558                 fanboysAnnoyanceListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_dark));
559             } else {
560                 fanboysAnnoyanceListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_light));
561             }
562         } else {  // Fanboy's Annoyance List is off.
563             // Turn the switch off.
564             fanboysAnnoyanceListSwitch.setChecked(false);
565
566             // Set the icon according to the theme.
567             if (darkTheme) {
568                 fanboysAnnoyanceListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_dark));
569             } else {
570                 fanboysAnnoyanceListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_light));
571             }
572         }
573
574         // Only enable Fanboy's Social Blocking List if Fanboy's Annoyance List is off.
575         if (fanboysAnnoyanceListInt == 0) {  // Fanboy's Annoyance List is on.
576             // Enable Fanboy's Social Blocking List.  Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
577             if (fanboysSocialBlockingListInt == 1) {  // Fanboy's Social Blocking List is on.
578                 // Enable the switch and turn it on.
579                 fanboysSocialBlockingListSwitch.setEnabled(true);
580                 fanboysSocialBlockingListSwitch.setChecked(true);
581
582                 // Set the icon according to the theme.
583                 if (darkTheme) {
584                     fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_dark));
585                 } else {
586                     fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_light));
587                 }
588             } else {  // Fanboy's Social Blocking List is off.
589                 // Enable the switch but turn it off.
590                 fanboysSocialBlockingListSwitch.setEnabled(true);
591                 fanboysSocialBlockingListSwitch.setChecked(false);
592
593                 // Set the icon according to the theme.
594                 if (darkTheme) {
595                     fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_dark));
596                 } else {
597                     fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_light));
598                 }
599             }
600         } else {  // Fanboy's Annoyance List is on.
601             // Disable Fanboy's Social Blocking List.  Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
602             if (fanboysSocialBlockingListInt == 1) {  // Fanboy's Social Blocking List is on.
603                 // Disable the switch but turn it on.
604                 fanboysSocialBlockingListSwitch.setEnabled(false);
605                 fanboysSocialBlockingListSwitch.setChecked(true);
606             } else {  // Fanboy's Social Blocking List is off.
607                 // Disable the switch and turn it off.
608                 fanboysSocialBlockingListSwitch.setEnabled(false);
609                 fanboysSocialBlockingListSwitch.setChecked(false);
610             }
611
612             // Set the icon according to the theme.
613             if (darkTheme) {
614                 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_ghosted_dark));
615             } else {
616                 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_ghosted_light));
617             }
618         }
619
620         // Set the UltraList status.  Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
621         if (ultraListInt == 1) {  // UltraList is on.
622             // Turn the switch on.
623             ultraListSwitch.setChecked(true);
624
625             // Set the icon according to the theme.
626             if (darkTheme) {
627                 ultraListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_enabled_dark));
628             } else {
629                 ultraListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_enabled_light));
630             }
631         } else {  // UltraList is off.
632             // Turn the switch off.
633             ultraListSwitch.setChecked(false);
634
635             // Set the icon according to the theme.
636             if (darkTheme) {
637                 ultraListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_disabled_dark));
638             } else {
639                 ultraListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_disabled_light));
640             }
641         }
642
643         // Set the UltraPrivacy status.  Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
644         if (ultraPrivacyInt == 1) {  // UltraPrivacy is on.
645             // Turn the switch on.
646             ultraPrivacySwitch.setChecked(true);
647
648             // Set the icon according to the theme.
649             if (darkTheme) {
650                 ultraPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_enabled_dark));
651             } else {
652                 ultraPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_enabled_light));
653             }
654         } else {  // EasyPrivacy is off.
655             // Turn the switch off.
656             ultraPrivacySwitch.setChecked(false);
657
658             // Set the icon according to the theme.
659             if (darkTheme) {
660                 ultraPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_disabled_dark));
661             } else {
662                 ultraPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_disabled_light));
663             }
664         }
665
666         // Set the third-party resource blocking status.  Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
667         if (blockAllThirdPartyRequestsInt == 1) {  // Blocking all third-party requests is on.
668             // Turn the switch on.
669             blockAllThirdPartyRequestsSwitch.setChecked(true);
670
671             // Set the icon according to the theme.
672             if (darkTheme) {
673                 blockAllThirdPartyRequestsImageView.setImageDrawable(resources.getDrawable(R.drawable.block_all_third_party_requests_enabled_dark));
674             } else {
675                 blockAllThirdPartyRequestsImageView.setImageDrawable(resources.getDrawable(R.drawable.block_all_third_party_requests_enabled_light));
676             }
677         } else {  // Blocking all third-party requests is off.
678             // Turn the switch off.
679             blockAllThirdPartyRequestsSwitch.setChecked(false);
680
681             // Set the icon according to the theme.
682             if (darkTheme) {
683                 blockAllThirdPartyRequestsImageView.setImageDrawable(resources.getDrawable(R.drawable.block_all_third_party_requests_disabled_dark));
684             } else {
685                 blockAllThirdPartyRequestsImageView.setImageDrawable(resources.getDrawable(R.drawable.block_all_third_party_requests_disabled_light));
686             }
687         }
688
689         // Inflated a WebView to get the default user agent.
690         // `@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.
691         @SuppressLint("InflateParams") View bareWebViewLayout = inflater.inflate(R.layout.bare_webview, null, false);
692         WebView bareWebView = bareWebViewLayout.findViewById(R.id.bare_webview);
693         final String webViewDefaultUserAgentString = bareWebView.getSettings().getUserAgentString();
694
695         // Get a handle for the user agent array adapter.  This array does not contain the `System default` entry.
696         ArrayAdapter<CharSequence> userAgentNamesArray = ArrayAdapter.createFromResource(context, R.array.user_agent_names, R.layout.spinner_item);
697
698         // Get the positions of the user agent and the default user agent.
699         int userAgentArrayPosition = userAgentNamesArray.getPosition(currentUserAgentName);
700         int defaultUserAgentArrayPosition = userAgentNamesArray.getPosition(defaultUserAgentName);
701
702         // Get a handle for the user agent data array.  This array does not contain the `System default` entry.
703         String[] userAgentDataArray = resources.getStringArray(R.array.user_agent_data);
704
705         // Set the user agent text.
706         if (currentUserAgentName.equals(getString(R.string.system_default_user_agent))) {  // Use the system default user agent.
707             // Set the user agent according to the system default.
708             switch (defaultUserAgentArrayPosition) {
709                 case MainWebViewActivity.UNRECOGNIZED_USER_AGENT:  // The default user agent name is not on the canonical list.
710                     // This is probably because it was set in an older version of Privacy Browser before the switch to persistent user agent names.
711                     userAgentTextView.setText(defaultUserAgentName);
712                     break;
713
714                 case MainWebViewActivity.SETTINGS_WEBVIEW_DEFAULT_USER_AGENT:
715                     // Display the `WebView` default user agent.
716                     userAgentTextView.setText(webViewDefaultUserAgentString);
717                     break;
718
719                 case MainWebViewActivity.SETTINGS_CUSTOM_USER_AGENT:
720                     // Display the custom user agent.
721                     userAgentTextView.setText(defaultCustomUserAgentString);
722                     break;
723
724                 default:
725                     // Get the user agent string from the user agent data array.
726                     userAgentTextView.setText(userAgentDataArray[defaultUserAgentArrayPosition]);
727             }
728         } else if (userAgentArrayPosition == MainWebViewActivity.UNRECOGNIZED_USER_AGENT) {  // A custom user agent is stored in the current user agent name.
729             // Set the user agent spinner to `Custom user agent`.
730             userAgentSpinner.setSelection(MainWebViewActivity.DOMAINS_CUSTOM_USER_AGENT);
731
732             // Hide the user agent TextView.
733             userAgentTextView.setVisibility(View.GONE);
734
735             // Show the custom user agent EditText and set the current user agent name as the text.
736             customUserAgentEditText.setVisibility(View.VISIBLE);
737             customUserAgentEditText.setText(currentUserAgentName);
738         } else {  // The user agent name contains one of the canonical user agents.
739             // 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.
740             userAgentSpinner.setSelection(userAgentArrayPosition + 1);
741
742             // Show the user agent TextView.
743             userAgentTextView.setVisibility(View.VISIBLE);
744
745             // Hide the custom user agent EditText.
746             customUserAgentEditText.setVisibility(View.GONE);
747
748             // Set the user agent text.
749             if (userAgentArrayPosition == MainWebViewActivity.DOMAINS_WEBVIEW_DEFAULT_USER_AGENT) {  // The WebView default user agent is selected.
750                 // Display the WebView default user agent.
751                 userAgentTextView.setText(webViewDefaultUserAgentString);
752             } else {  // A user agent besides the default is selected.
753                 // 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.
754                 userAgentTextView.setText(userAgentDataArray[userAgentArrayPosition + 1]);
755             }
756         }
757
758         // Open the user agent spinner when the text view is clicked.
759         userAgentTextView.setOnClickListener((View v) -> {
760             // Open the user agent spinner.
761             userAgentSpinner.performClick();
762         });
763
764         // Set the selected font size.
765         int fontSizeArrayPosition = fontSizeEntryValuesArrayAdapter.getPosition(String.valueOf(fontSizeInt));
766         fontSizeSpinner.setSelection(fontSizeArrayPosition);
767
768         // Set the default font size text.
769         int defaultFontSizeArrayPosition = fontSizeEntryValuesArrayAdapter.getPosition(defaultFontSizeString);
770         fontSizeTextView.setText(fontSizeArrayAdapter.getItem(defaultFontSizeArrayPosition));
771
772         // Set the display options for the font size TextView.
773         if (fontSizeArrayPosition == 0) {  // System default font size is selected.  Display `fontSizeTextView`.
774             fontSizeTextView.setVisibility(View.VISIBLE);
775         } else {  // A custom font size is specified.  Hide `fontSizeTextView`.
776             fontSizeTextView.setVisibility(View.GONE);
777         }
778
779         // Open the font size spinner when the TextView is clicked.
780         fontSizeTextView.setOnClickListener((View v) -> {
781             // Open the user agent spinner.
782             fontSizeSpinner.performClick();
783         });
784
785         // Display the swipe to refresh selection in the spinner.
786         swipeToRefreshSpinner.setSelection(swipeToRefreshInt);
787
788         // Set the swipe to refresh text.
789         if (defaultSwipeToRefresh) {
790             swipeToRefreshTextView.setText(swipeToRefreshArrayAdapter.getItem(DomainsDatabaseHelper.ENABLED));
791         } else {
792             swipeToRefreshTextView.setText(swipeToRefreshArrayAdapter.getItem(DomainsDatabaseHelper.DISABLED));
793         }
794
795         // Set the swipe to refresh icon and TextView settings.  Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
796         switch (swipeToRefreshInt) {
797             case DomainsDatabaseHelper.SYSTEM_DEFAULT:
798                 if (defaultSwipeToRefresh) {  // Swipe to refresh is enabled by default.
799                     // Set the icon according to the theme.
800                     if (darkTheme) {
801                         swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_enabled_dark));
802                     } else {
803                         swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_enabled_light));
804                     }
805                 } else {  // Swipe to refresh is disabled by default
806                     // Set the icon according to the theme.
807                     if (darkTheme) {
808                         swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_disabled_dark));
809                     } else {
810                         swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_disabled_light));
811                     }
812                 }
813
814                 // Show the swipe to refresh TextView.
815                 swipeToRefreshTextView.setVisibility(View.VISIBLE);
816                 break;
817
818             case DomainsDatabaseHelper.ENABLED:
819                 // Set the icon according to the theme.
820                 if (darkTheme) {
821                     swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_enabled_dark));
822                 } else {
823                     swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_enabled_light));
824                 }
825
826                 // Hide the swipe to refresh TextView.`
827                 swipeToRefreshTextView.setVisibility(View.GONE);
828                 break;
829
830             case DomainsDatabaseHelper.DISABLED:
831                 // Set the icon according to the theme.
832                 if (darkTheme) {
833                     swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_disabled_dark));
834                 } else {
835                     swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_disabled_light));
836                 }
837
838                 // Hide the swipe to refresh TextView.
839                 swipeToRefreshTextView.setVisibility(View.GONE);
840         }
841
842         // Open the swipe to refresh spinner when the TextView is clicked.
843         swipeToRefreshTextView.setOnClickListener((View v) -> {
844             // Open the swipe to refresh spinner.
845             swipeToRefreshSpinner.performClick();
846         });
847
848         // Display the night mode in the spinner.
849         nightModeSpinner.setSelection(nightModeInt);
850
851         // Set the default night mode text.
852         if (defaultNightMode) {
853             nightModeTextView.setText(nightModeArrayAdapter.getItem(DomainsDatabaseHelper.ENABLED));
854         } else {
855             nightModeTextView.setText(nightModeArrayAdapter.getItem(DomainsDatabaseHelper.DISABLED));
856         }
857
858         // Set the night mode icon and TextView settings.  Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
859         switch (nightModeInt) {
860             case DomainsDatabaseHelper.SYSTEM_DEFAULT:
861                 if (defaultNightMode) {  // Night mode enabled by default.
862                     // Set the icon according to the theme.
863                     if (darkTheme) {
864                         nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_dark));
865                     } else {
866                         nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_light));
867                     }
868                 } else {  // Night mode disabled by default.
869                     // Set the icon according to the theme.
870                     if (darkTheme) {
871                         nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_dark));
872                     } else {
873                         nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_light));
874                     }
875                 }
876
877                 // Show night mode TextView.
878                 nightModeTextView.setVisibility(View.VISIBLE);
879                 break;
880
881             case DomainsDatabaseHelper.ENABLED:
882                 // Set the icon according to the theme.
883                 if (darkTheme) {
884                     nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_dark));
885                 } else {
886                     nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_light));
887                 }
888
889                 // Hide the night mode TextView.
890                 nightModeTextView.setVisibility(View.GONE);
891                 break;
892
893             case DomainsDatabaseHelper.DISABLED:
894                 // Set the icon according to the theme.
895                 if (darkTheme) {
896                     nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_dark));
897                 } else {
898                     nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_light));
899                 }
900
901                 // Hide the night mode TextView.
902                 nightModeTextView.setVisibility(View.GONE);
903                 break;
904         }
905
906         // Open the night mode spinner when the TextView is clicked.
907         nightModeTextView.setOnClickListener((View v) -> {
908             // Open the night mode spinner.
909             nightModeSpinner.performClick();
910         });
911
912         // Display the wide viewport in the spinner.
913         wideViewportSpinner.setSelection(wideViewportInt);
914
915         // Set the default wide viewport text.
916         if (defaultWideViewport) {
917             wideViewportTextView.setText(wideViewportArrayAdapter.getItem(DomainsDatabaseHelper.ENABLED));
918         } else {
919             wideViewportTextView.setText(wideViewportArrayAdapter.getItem(DomainsDatabaseHelper.DISABLED));
920         }
921
922         // Set the wide viewport icon and text view settings.  Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
923         switch (wideViewportInt) {
924             case DomainsDatabaseHelper.SYSTEM_DEFAULT:
925                 if (defaultWideViewport) {  // Wide viewport enabled by default.
926                     // Set the icon according to the theme.
927                     if (darkTheme) {
928                         wideViewportImageView.setImageDrawable(resources.getDrawable(R.drawable.wide_viewport_enabled_dark));
929                     } else {
930                         wideViewportImageView.setImageDrawable(resources.getDrawable(R.drawable.wide_viewport_enabled_light));
931                     }
932                 } else {  // Wide viewport disabled by default.
933                     if (darkTheme) {
934                         wideViewportImageView.setImageDrawable(resources.getDrawable(R.drawable.wide_viewport_disabled_dark));
935                     } else {
936                         wideViewportImageView.setImageDrawable(resources.getDrawable(R.drawable.wide_viewport_disabled_light));
937                     }
938                 }
939
940                 // Show the wide viewport text view.
941                 wideViewportTextView.setVisibility(View.VISIBLE);
942                 break;
943
944             case DomainsDatabaseHelper.ENABLED:
945                 // Set the icon according to the theme.
946                 if (darkTheme) {
947                     wideViewportImageView.setImageDrawable(resources.getDrawable(R.drawable.wide_viewport_enabled_dark));
948                 } else {
949                     wideViewportImageView.setImageDrawable(resources.getDrawable(R.drawable.wide_viewport_enabled_light));
950                 }
951
952                 // Hide the wide viewport text view.
953                 wideViewportTextView.setVisibility(View.GONE);
954                 break;
955
956             case DomainsDatabaseHelper.DISABLED:
957                 // Set the icon according to the theme.
958                 if (darkTheme) {
959                     wideViewportImageView.setImageDrawable(resources.getDrawable(R.drawable.wide_viewport_disabled_dark));
960                 } else {
961                     wideViewportImageView.setImageDrawable(resources.getDrawable(R.drawable.wide_viewport_disabled_light));
962                 }
963
964                 // Hide the wide viewport text view.
965                 wideViewportTextView.setVisibility(View.GONE);
966                 break;
967         }
968
969         // Open the wide viewport spinner when the text view is clicked.
970         wideViewportTextView.setOnClickListener((View view) -> {
971             // Open the wide viewport spinner.
972             wideViewportSpinner.performClick();
973         });
974
975         // Display the website images mode in the spinner.
976         displayWebpageImagesSpinner.setSelection(displayImagesInt);
977
978         // Set the default display images text.
979         if (defaultDisplayWebpageImages) {
980             displayImagesTextView.setText(displayImagesArrayAdapter.getItem(DomainsDatabaseHelper.ENABLED));
981         } else {
982             displayImagesTextView.setText(displayImagesArrayAdapter.getItem(DomainsDatabaseHelper.DISABLED));
983         }
984
985         // Set the display website images icon and text view settings.  Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
986         switch (displayImagesInt) {
987             case DomainsDatabaseHelper.SYSTEM_DEFAULT:
988                 if (defaultDisplayWebpageImages) {  // Display webpage images enabled by default.
989                     // Set the icon according to the theme.
990                     if (darkTheme) {
991                         displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_dark));
992                     } else {
993                         displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_light));
994                     }
995                 } else {  // Display webpage images disabled by default.
996                     // Set the icon according to the theme.
997                     if (darkTheme) {
998                         displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_dark));
999                     } else {
1000                         displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_light));
1001                     }
1002                 }
1003
1004                 // Show the display images text view.
1005                 displayImagesTextView.setVisibility(View.VISIBLE);
1006                 break;
1007
1008             case DomainsDatabaseHelper.ENABLED:
1009                 // Set the icon according to the theme.
1010                 if (darkTheme) {
1011                     displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_dark));
1012                 } else {
1013                     displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_light));
1014                 }
1015
1016                 // Hide the display images text view.
1017                 displayImagesTextView.setVisibility(View.GONE);
1018                 break;
1019
1020             case DomainsDatabaseHelper.DISABLED:
1021                 // Set the icon according to the theme.
1022                 if (darkTheme) {
1023                     displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_dark));
1024                 } else {
1025                     displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_light));
1026                 }
1027
1028                 // Hide the display images text view.
1029                 displayImagesTextView.setVisibility(View.GONE);
1030                 break;
1031         }
1032
1033         // Open the display images spinner when the text view is clicked.
1034         displayImagesTextView.setOnClickListener((View view) -> {
1035             // Open the user agent spinner.
1036             displayWebpageImagesSpinner.performClick();
1037         });
1038         
1039         // Set the pinned SSL certificate icon.
1040         if (pinnedSslCertificateInt == 1) {  // Pinned SSL certificate is enabled.  Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
1041             // Check the switch.
1042             pinnedSslCertificateSwitch.setChecked(true);
1043
1044             // Set the icon according to the theme.
1045             if (darkTheme) {
1046                 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_dark));
1047             } else {
1048                 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_light));
1049             }
1050         } else {  // Pinned SSL certificate is disabled.
1051             // Uncheck the switch.
1052             pinnedSslCertificateSwitch.setChecked(false);
1053
1054             // Set the icon according to the theme.
1055             if (darkTheme) {
1056                 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_dark));
1057             } else {
1058                 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_light));
1059             }
1060         }
1061
1062         // Store the current date.
1063         Date currentDate = Calendar.getInstance().getTime();
1064
1065         // Setup the string builders to display the general certificate information in blue.  `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
1066         savedSslIssuedToONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), savedSslIssuedToONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1067         savedSslIssuedToUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), savedSslIssuedToUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1068         savedSslIssuedByCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), savedSslIssuedByCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1069         savedSslIssuedByONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), savedSslIssuedByONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1070         savedSslIssuedByUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), savedSslIssuedByUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1071
1072         // Check the certificate Common Name against the domain name.
1073         boolean savedSslCommonNameMatchesDomainName = checkDomainNameAgainstCertificate(domainNameString, savedSslIssuedToCNameString);
1074
1075         // Format the issued to Common Name color.  `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
1076         if (savedSslCommonNameMatchesDomainName) {
1077             savedSslIssuedToCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), savedSslIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1078         } else {
1079             savedSslIssuedToCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), savedSslIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1080         }
1081
1082         //  Format the start date color.  `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
1083         if ((savedSslStartDate != null) && savedSslStartDate.after(currentDate)) {  // The certificate start date is in the future.
1084             savedSslStartDateStringBuilder.setSpan(redColorSpan, startDateLabel.length(), savedSslStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1085         } else {  // The certificate start date is in the past.
1086             savedSslStartDateStringBuilder.setSpan(blueColorSpan, startDateLabel.length(), savedSslStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1087         }
1088
1089         // Format the end date color.  `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
1090         if ((savedSslEndDate != null) && savedSslEndDate.before(currentDate)) {  // The certificate end date is in the past.
1091             savedSslEndDateStringBuilder.setSpan(redColorSpan, endDateLabel.length(), savedSslEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1092         } else {  // The certificate end date is in the future.
1093             savedSslEndDateStringBuilder.setSpan(blueColorSpan, endDateLabel.length(), savedSslEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1094         }
1095
1096         // Display the saved website SSL certificate strings.
1097         savedSslIssuedToCNameTextView.setText(savedSslIssuedToCNameStringBuilder);
1098         savedSslIssuedToONameTextView.setText(savedSslIssuedToONameStringBuilder);
1099         savedSslIssuedToUNameTextView.setText(savedSslIssuedToUNameStringBuilder);
1100         savedSslIssuedByCNameTextView.setText(savedSslIssuedByCNameStringBuilder);
1101         savedSslIssuedByONameTextView.setText(savedSslIssuedByONameStringBuilder);
1102         savedSslIssuedByUNameTextView.setText(savedSslIssuedByUNameStringBuilder);
1103         savedSslStartDateTextView.setText(savedSslStartDateStringBuilder);
1104         savedSslEndDateTextView.setText(savedSslEndDateStringBuilder);
1105
1106         // Populate the current website SSL certificate if there is one.
1107         if (DomainsActivity.sslIssuedToCName != null) {
1108             // Get dates from the raw long values.
1109             Date currentSslStartDate = new Date(DomainsActivity.sslStartDateLong);
1110             Date currentSslEndDate = new Date(DomainsActivity.sslEndDateLong);
1111
1112             // Create a spannable string builder for each text view that needs multiple colors of text.
1113             SpannableStringBuilder currentSslIssuedToCNameStringBuilder = new SpannableStringBuilder(cNameLabel + DomainsActivity.sslIssuedToCName);
1114             SpannableStringBuilder currentSslIssuedToONameStringBuilder = new SpannableStringBuilder(oNameLabel + DomainsActivity.sslIssuedToOName);
1115             SpannableStringBuilder currentSslIssuedToUNameStringBuilder = new SpannableStringBuilder(uNameLabel + DomainsActivity.sslIssuedToUName);
1116             SpannableStringBuilder currentSslIssuedByCNameStringBuilder = new SpannableStringBuilder(cNameLabel + DomainsActivity.sslIssuedByCName);
1117             SpannableStringBuilder currentSslIssuedByONameStringBuilder = new SpannableStringBuilder(oNameLabel + DomainsActivity.sslIssuedByOName);
1118             SpannableStringBuilder currentSslIssuedByUNameStringBuilder = new SpannableStringBuilder(uNameLabel + DomainsActivity.sslIssuedByUName);
1119             SpannableStringBuilder currentSslStartDateStringBuilder = new SpannableStringBuilder(startDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG)
1120                     .format(currentSslStartDate));
1121             SpannableStringBuilder currentSslEndDateStringBuilder = new SpannableStringBuilder(endDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG)
1122                     .format(currentSslEndDate));
1123
1124             // Setup the string builders to display the general certificate information in blue.  `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
1125             currentSslIssuedToONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), currentSslIssuedToONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1126             currentSslIssuedToUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), currentSslIssuedToUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1127             currentSslIssuedByCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), currentSslIssuedByCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1128             currentSslIssuedByONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), currentSslIssuedByONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1129             currentSslIssuedByUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), currentSslIssuedByUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1130
1131             // Check the certificate Common Name against the domain name.
1132             boolean currentSslCommonNameMatchesDomainName = checkDomainNameAgainstCertificate(domainNameString, DomainsActivity.sslIssuedToCName);
1133
1134             // Format the issued to Common Name color.  `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
1135             if (currentSslCommonNameMatchesDomainName) {
1136                 currentSslIssuedToCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), currentSslIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1137             } else {
1138                 currentSslIssuedToCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), currentSslIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1139             }
1140
1141             //  Format the start date color.  `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
1142             if (currentSslStartDate.after(currentDate)) {  // The certificate start date is in the future.
1143                 currentSslStartDateStringBuilder.setSpan(redColorSpan, startDateLabel.length(), currentSslStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1144             } else {  // The certificate start date is in the past.
1145                 currentSslStartDateStringBuilder.setSpan(blueColorSpan, startDateLabel.length(), currentSslStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1146             }
1147
1148             // Format the end date color.  `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
1149             if (currentSslEndDate.before(currentDate)) {  // The certificate end date is in the past.
1150                 currentSslEndDateStringBuilder.setSpan(redColorSpan, endDateLabel.length(), currentSslEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1151             } else {  // The certificate end date is in the future.
1152                 currentSslEndDateStringBuilder.setSpan(blueColorSpan, endDateLabel.length(), currentSslEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1153             }
1154
1155             // Display the current website SSL certificate strings.
1156             currentSslIssuedToCNameTextView.setText(currentSslIssuedToCNameStringBuilder);
1157             currentSslIssuedToONameTextView.setText(currentSslIssuedToONameStringBuilder);
1158             currentSslIssuedToUNameTextView.setText(currentSslIssuedToUNameStringBuilder);
1159             currentSslIssuedByCNameTextView.setText(currentSslIssuedByCNameStringBuilder);
1160             currentSslIssuedByONameTextView.setText(currentSslIssuedByONameStringBuilder);
1161             currentSslIssuedByUNameTextView.setText(currentSslIssuedByUNameStringBuilder);
1162             currentSslStartDateTextView.setText(currentSslStartDateStringBuilder);
1163             currentSslEndDateTextView.setText(currentSslEndDateStringBuilder);
1164         }
1165
1166         // Set the initial display status of the SSL certificates card views.
1167         if (pinnedSslCertificateSwitch.isChecked()) {  // An SSL certificate is pinned.
1168             // Set the visibility of the saved SSL certificate.
1169             if (savedSslIssuedToCNameString == null) {
1170                 savedSslCardView.setVisibility(View.GONE);
1171             } else {
1172                 savedSslCardView.setVisibility(View.VISIBLE);
1173             }
1174
1175             // Set the visibility of the current website SSL certificate.
1176             if (DomainsActivity.sslIssuedToCName == null) {  // There is no current SSL certificate.
1177                 // Hide the SSL certificate.
1178                 currentSslCardView.setVisibility(View.GONE);
1179
1180                 // Show the instruction.
1181                 noCurrentWebsiteCertificateTextView.setVisibility(View.VISIBLE);
1182             } else {  // There is a current SSL certificate.
1183                 // Show the SSL certificate.
1184                 currentSslCardView.setVisibility(View.VISIBLE);
1185
1186                 // Hide the instruction.
1187                 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
1188             }
1189
1190             // Set the status of the radio buttons and the card view backgrounds.
1191             if (savedSslCardView.getVisibility() == View.VISIBLE) {  // The saved SSL certificate is displayed.
1192                 // Check the saved SSL certificate radio button.
1193                 savedSslCertificateRadioButton.setChecked(true);
1194
1195                 // Uncheck the current website SSL certificate radio button.
1196                 currentWebsiteCertificateRadioButton.setChecked(false);
1197
1198                 // Darken the background of the current website SSL certificate linear layout according to the theme.
1199                 if (darkTheme) {
1200                     currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1201                 } else {
1202                     currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1203                 }
1204             } else if (currentSslCardView.getVisibility() == View.VISIBLE) {  // The saved SSL certificate is hidden but the current website SSL certificate is visible.
1205                 // Check the current website SSL certificate radio button.
1206                 currentWebsiteCertificateRadioButton.setChecked(true);
1207
1208                 // Uncheck the saved SSL certificate radio button.
1209                 savedSslCertificateRadioButton.setChecked(false);
1210             } else {  // Neither SSL certificate is visible.
1211                 // Uncheck both radio buttons.
1212                 savedSslCertificateRadioButton.setChecked(false);
1213                 currentWebsiteCertificateRadioButton.setChecked(false);
1214             }
1215         } else {  // An SSL certificate is not pinned.
1216             // Hide the SSl certificates and instructions.
1217             savedSslCardView.setVisibility(View.GONE);
1218             currentSslCardView.setVisibility(View.GONE);
1219             noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
1220
1221             // Uncheck the radio buttons.
1222             savedSslCertificateRadioButton.setChecked(false);
1223             currentWebsiteCertificateRadioButton.setChecked(false);
1224         }
1225
1226         // Set the pinned IP addresses icon.
1227         if (pinnedIpAddressesInt == 1) {  // Pinned IP addresses is enabled.  Once the minimum API >= 21 a selector can be sued as the tint mode instead of specifying different icons.
1228             // Check the switch.
1229             pinnedIpAddressesSwitch.setChecked(true);
1230
1231             // Set the icon according to the theme.
1232             if (darkTheme) {
1233                 pinnedIpAddressesImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_dark));
1234             } else {
1235                 pinnedIpAddressesImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_light));
1236             }
1237         } else {  // Pinned IP Addresses is disabled.
1238             // Uncheck the switch.
1239             pinnedIpAddressesSwitch.setChecked(false);
1240
1241             // Set the icon according to the theme.
1242             if (darkTheme) {
1243                 pinnedIpAddressesImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_dark));
1244             } else {
1245                 pinnedIpAddressesImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_light));
1246             }
1247         }
1248
1249         // Populate the saved and current IP addresses.
1250         savedIpAddressesTextView.setText(savedIpAddresses);
1251         currentIpAddressesTextView.setText(DomainsActivity.currentIpAddresses);
1252
1253         // Set the initial display status of the IP addresses card views.
1254         if (pinnedIpAddressesSwitch.isChecked()) {  // IP addresses are pinned.
1255             // Set the visibility of the saved IP addresses.
1256             if (savedIpAddresses == null) {  // There are no saved IP addresses.
1257                 savedIpAddressesCardView.setVisibility(View.GONE);
1258             } else {  // There are saved IP addresses.
1259                 savedIpAddressesCardView.setVisibility(View.VISIBLE);
1260             }
1261
1262             // Set the visibility of the current IP addresses.
1263             currentIpAddressesCardView.setVisibility(View.VISIBLE);
1264
1265             // Set the status of the radio buttons and the card view backgrounds.
1266             if (savedIpAddressesCardView.getVisibility() == View.VISIBLE) {  // The saved IP addresses are displayed.
1267                 // Check the saved IP addresses radio button.
1268                 savedIpAddressesRadioButton.setChecked(true);
1269
1270                 // Uncheck the current IP addresses radio button.
1271                 currentIpAddressesRadioButton.setChecked(false);
1272
1273                 // Darken the background of the current IP addresses linear layout according to the theme.
1274                 if (darkTheme) {
1275                     currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1276                 } else {
1277                     currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1278                 }
1279             } else {  // The saved IP addresses are hidden.
1280                 // Check the current IP addresses radio button.
1281                 currentIpAddressesRadioButton.setChecked(true);
1282
1283                 // Uncheck the saved IP addresses radio button.
1284                 savedIpAddressesRadioButton.setChecked(false);
1285             }
1286         } else {  // IP addresses are not pinned.
1287             // Hide the IP addresses card views.
1288             savedIpAddressesCardView.setVisibility(View.GONE);
1289             currentIpAddressesCardView.setVisibility(View.GONE);
1290
1291             // Uncheck the radio buttons.
1292             savedIpAddressesRadioButton.setChecked(false);
1293             currentIpAddressesRadioButton.setChecked(false);
1294         }
1295
1296
1297         // Set the JavaScript switch listener.
1298         javaScriptSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1299             if (isChecked) {  // JavaScript is enabled.
1300                 // Update the JavaScript icon.
1301                 javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.javascript_enabled));
1302
1303                 // Enable the DOM storage `Switch`.
1304                 domStorageSwitch.setEnabled(true);
1305
1306                 // Update the DOM storage icon.
1307                 if (domStorageSwitch.isChecked()) {  // DOM storage is enabled.
1308                     domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_enabled));
1309                 } else {  // DOM storage is disabled.
1310                     // Set the icon according to the theme.
1311                     if (darkTheme) {
1312                         domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_dark));
1313                     } else {
1314                         domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_light));
1315                     }
1316                 }
1317             } else {  // JavaScript is disabled.
1318                 // Update the JavaScript icon.
1319                 javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.privacy_mode));
1320
1321                 // Disable the DOM storage `Switch`.
1322                 domStorageSwitch.setEnabled(false);
1323
1324                 // Set the DOM storage icon according to the theme.
1325                 if (darkTheme) {
1326                     domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_dark));
1327                 } else {
1328                     domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_light));
1329                 }
1330             }
1331         });
1332
1333         // Set the first-party cookies switch listener.
1334         firstPartyCookiesSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1335             if (isChecked) {  // First-party cookies are enabled.
1336                 // Update the first-party cookies icon.
1337                 firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_enabled));
1338
1339                 // Enable the third-party cookies switch.
1340                 thirdPartyCookiesSwitch.setEnabled(true);
1341
1342                 // Update the third-party cookies icon.
1343                 if (thirdPartyCookiesSwitch.isChecked()) {  // Third-party cookies are enabled.
1344                     thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_warning));
1345                 } else {  // Third-party cookies are disabled.
1346                     // Set the third-party cookies icon according to the theme.
1347                     if (darkTheme) {
1348                         thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_dark));
1349                     } else {
1350                         thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_light));
1351                     }
1352                 }
1353             } else {  // First-party cookies are disabled.
1354                 // Update the first-party cookies icon according to the theme.
1355                 if (darkTheme) {
1356                     firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_dark));
1357                 } else {
1358                     firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_light));
1359                 }
1360
1361                 // Disable the third-party cookies switch.
1362                 thirdPartyCookiesSwitch.setEnabled(false);
1363
1364                 // Set the third-party cookies icon according to the theme.
1365                 if (darkTheme) {
1366                     thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_ghosted_dark));
1367                 } else {
1368                     thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_ghosted_light));
1369                 }
1370             }
1371         });
1372
1373         // Set the third-party cookies switch listener.
1374         thirdPartyCookiesSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1375             // Update the icon.
1376             if (isChecked) {
1377                 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_warning));
1378             } else {
1379                 // Update the third-party cookies icon according to the theme.
1380                 if (darkTheme) {
1381                     thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_dark));
1382                 } else {
1383                     thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_light));
1384                 }
1385             }
1386         });
1387
1388         // Set the DOM Storage switch listener.
1389         domStorageSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1390             // Update the icon.
1391             if (isChecked) {
1392                 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_enabled));
1393             } else {
1394                 // Set the icon according to the theme.
1395                 if (darkTheme) {
1396                     domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_dark));
1397                 } else {
1398                     domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_light));
1399                 }
1400             }
1401         });
1402
1403         // Set the form data switch listener.  It can be removed once the minimum API >= 26.
1404         if (Build.VERSION.SDK_INT < 26) {
1405             formDataSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1406                 // Update the icon.
1407                 if (isChecked) {
1408                     formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_enabled));
1409                 } else {
1410                     // Set the icon according to the theme.
1411                     if (darkTheme) {
1412                         formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_disabled_dark));
1413                     } else {
1414                         formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_disabled_light));
1415                     }
1416                 }
1417             });
1418         }
1419
1420         // Set the EasyList switch listener.
1421         easyListSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1422             // Update the icon.
1423             if (isChecked) {  // EasyList is on.
1424                 // Set the icon according to the theme.
1425                 if (darkTheme) {
1426                     easyListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_enabled_dark));
1427                 } else {
1428                     easyListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_enabled_light));
1429                 }
1430             } else {  // EasyList is off.
1431                 // Set the icon according to the theme.
1432                 if (darkTheme) {
1433                     easyListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_disabled_dark));
1434                 } else {
1435                     easyListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_disabled_light));
1436                 }
1437             }
1438         });
1439
1440         // Set the EasyPrivacy switch listener.
1441         easyPrivacySwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1442             // Update the icon.
1443             if (isChecked) {  // EasyPrivacy is on.
1444                 // Set the icon according to the theme.
1445                 if (darkTheme) {
1446                     easyPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_enabled_dark));
1447                 } else {
1448                     easyPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_enabled_light));
1449                 }
1450             } else {  // EasyPrivacy is off.
1451                 // Set the icon according to the theme.
1452                 if (darkTheme) {
1453                     easyPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_disabled_dark));
1454                 } else {
1455                     easyPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_disabled_light));
1456                 }
1457             }
1458         });
1459
1460         // Set the Fanboy's Annoyance List switch listener.
1461         fanboysAnnoyanceListSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1462             // Update the icon and Fanboy's Social Blocking List.
1463             if (isChecked) {  // Fanboy's Annoyance List is on.
1464                 // Set the icon according to the theme.
1465                 if (darkTheme) {
1466                     fanboysAnnoyanceListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_dark));
1467                 } else {
1468                     fanboysAnnoyanceListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_light));
1469                 }
1470
1471                 // Disable the Fanboy's Social Blocking List switch.
1472                 fanboysSocialBlockingListSwitch.setEnabled(false);
1473
1474                 // Update the Fanboy's Social Blocking List icon according to the theme.
1475                 if (darkTheme) {
1476                     fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_ghosted_dark));
1477                 } else {
1478                     fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_ghosted_light));
1479                 }
1480             } else {  // Fanboy's Annoyance List is off.
1481                 // Set the icon according to the theme.
1482                 if (darkTheme) {
1483                     fanboysAnnoyanceListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_dark));
1484                 } else {
1485                     fanboysAnnoyanceListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_light));
1486                 }
1487
1488                 // Enable the Fanboy's Social Blocking List switch.
1489                 fanboysSocialBlockingListSwitch.setEnabled(true);
1490
1491                 // Update the Fanboy's Social Blocking List icon.
1492                 if (fanboysSocialBlockingListSwitch.isChecked()) {  // Fanboy's Social Blocking List is on.
1493                     // Update the icon according to the theme.
1494                     if (darkTheme) {
1495                         fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_dark));
1496                     } else {
1497                         fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_light));
1498                     }
1499                 } else {  // Fanboy's Social Blocking List is off.
1500                     // Update the icon according to the theme.
1501                     if (darkTheme) {
1502                         fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_dark));
1503                     } else {
1504                         fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_light));
1505                     }
1506                 }
1507             }
1508
1509         });
1510
1511         // Set the Fanboy's Social Blocking List switch listener.
1512         fanboysSocialBlockingListSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1513             // Update the icon.
1514             if (isChecked) {  // Fanboy's Social Blocking List is on.
1515                 // Set the icon according to the theme.
1516                 if (darkTheme) {
1517                     fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_dark));
1518                 } else {
1519                     fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_light));
1520                 }
1521             } else {  // Fanboy's Social Blocking List is off.
1522                 // Set the icon according to the theme.
1523                 if (darkTheme) {
1524                     fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_dark));
1525                 } else {
1526                     fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_light));
1527                 }
1528             }
1529         });
1530
1531         // Set the UltraList switch listener.
1532         ultraListSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1533             // Update the icon.
1534             if (isChecked) {  // UltraList is on.
1535                 // Set the icon according to the theme.
1536                 if (darkTheme) {
1537                     ultraListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_enabled_dark));
1538                 } else {
1539                     ultraListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_enabled_light));
1540                 }
1541             } else {  // UltraList is off.
1542                 // Set the icon according to the theme.
1543                 if (darkTheme) {
1544                     ultraListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_disabled_dark));
1545                 } else {
1546                     ultraListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_disabled_light));
1547                 }
1548             }
1549         });
1550
1551         // Set the UltraPrivacy switch listener.
1552         ultraPrivacySwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1553             // Update the icon.
1554             if (isChecked) {  // UltraPrivacy is on.
1555                 // Set the icon according to the theme.
1556                 if (darkTheme) {
1557                     ultraPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_enabled_dark));
1558                 } else {
1559                     ultraPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_enabled_light));
1560                 }
1561             } else {  // UltraPrivacy is off.
1562                 // Set the icon according to the theme.
1563                 if (darkTheme) {
1564                     ultraPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_disabled_dark));
1565                 } else {
1566                     ultraPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_disabled_light));
1567                 }
1568             }
1569         });
1570
1571         // Set the block all third-party requests switch listener.
1572         blockAllThirdPartyRequestsSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1573             // Update the icon.
1574             if (isChecked) {  // Blocking all third-party requests is on.
1575                 // Set the icon according to the theme.
1576                 if (darkTheme) {
1577                     blockAllThirdPartyRequestsImageView.setImageDrawable(resources.getDrawable(R.drawable.block_all_third_party_requests_enabled_dark));
1578                 } else {
1579                     blockAllThirdPartyRequestsImageView.setImageDrawable(resources.getDrawable(R.drawable.block_all_third_party_requests_enabled_light));
1580                 }
1581             } else {  // Blocking all third-party requests is off.
1582                 // Set the icon according to the theme.
1583                 if (darkTheme) {
1584                     blockAllThirdPartyRequestsImageView.setImageDrawable(resources.getDrawable(R.drawable.block_all_third_party_requests_disabled_dark));
1585                 } else {
1586                     blockAllThirdPartyRequestsImageView.setImageDrawable(resources.getDrawable(R.drawable.block_all_third_party_requests_disabled_light));
1587                 }
1588             }
1589         });
1590
1591         // Set the user agent spinner listener.
1592         userAgentSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1593             @Override
1594             public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1595                 // Set the new user agent.
1596                 switch (position) {
1597                     case MainWebViewActivity.DOMAINS_SYSTEM_DEFAULT_USER_AGENT:
1598                         // Show the user agent TextView.
1599                         userAgentTextView.setVisibility(View.VISIBLE);
1600
1601                         // Hide the custom user agent EditText.
1602                         customUserAgentEditText.setVisibility(View.GONE);
1603
1604                         // Set the user text.
1605                         switch (defaultUserAgentArrayPosition) {
1606                             case MainWebViewActivity.UNRECOGNIZED_USER_AGENT:  // The default user agent name is not on the canonical list.
1607                                 // This is probably because it was set in an older version of Privacy Browser before the switch to persistent user agent names.
1608                                 userAgentTextView.setText(defaultUserAgentName);
1609                                 break;
1610
1611                             case MainWebViewActivity.SETTINGS_WEBVIEW_DEFAULT_USER_AGENT:
1612                                 // Display the `WebView` default user agent.
1613                                 userAgentTextView.setText(webViewDefaultUserAgentString);
1614                                 break;
1615
1616                             case MainWebViewActivity.SETTINGS_CUSTOM_USER_AGENT:
1617                                 // Display the custom user agent.
1618                                 userAgentTextView.setText(defaultCustomUserAgentString);
1619                                 break;
1620
1621                             default:
1622                                 // Get the user agent string from the user agent data array.
1623                                 userAgentTextView.setText(userAgentDataArray[defaultUserAgentArrayPosition]);
1624                         }
1625                         break;
1626
1627                     case MainWebViewActivity.DOMAINS_WEBVIEW_DEFAULT_USER_AGENT:
1628                         // Show the user agent TextView and set the text.
1629                         userAgentTextView.setVisibility(View.VISIBLE);
1630                         userAgentTextView.setText(webViewDefaultUserAgentString);
1631
1632                         // Hide the custom user agent EditTex.
1633                         customUserAgentEditText.setVisibility(View.GONE);
1634                         break;
1635
1636                     case MainWebViewActivity.DOMAINS_CUSTOM_USER_AGENT:
1637                         // Hide the user agent TextView.
1638                         userAgentTextView.setVisibility(View.GONE);
1639
1640                         // Show the custom user agent EditText and set the current user agent name as the text.
1641                         customUserAgentEditText.setVisibility(View.VISIBLE);
1642                         customUserAgentEditText.setText(currentUserAgentName);
1643                         break;
1644
1645                     default:
1646                         // Show the user agent TextView and set the text from the user agent data array, which has one less entry than the spinner, so the position must be decremented.
1647                         userAgentTextView.setVisibility(View.VISIBLE);
1648                         userAgentTextView.setText(userAgentDataArray[position - 1]);
1649
1650                         // Hide `customUserAgentEditText`.
1651                         customUserAgentEditText.setVisibility(View.GONE);
1652                 }
1653             }
1654
1655             @Override
1656             public void onNothingSelected(AdapterView<?> parent) {
1657                 // Do nothing.
1658             }
1659         });
1660
1661         // Set the font size spinner listener.
1662         fontSizeSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1663             @Override
1664             public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1665                 // Update the display options for `fontSizeTextView`.
1666                 if (position == 0) {  // System default font size has been selected.  Display `fontSizeTextView`.
1667                     fontSizeTextView.setVisibility(View.VISIBLE);
1668                 } else {  // A custom font size has been selected.  Hide `fontSizeTextView`.
1669                     fontSizeTextView.setVisibility(View.GONE);
1670                 }
1671             }
1672
1673             @Override
1674             public void onNothingSelected(AdapterView<?> parent) {
1675                 // Do nothing.
1676             }
1677         });
1678
1679         // Set the swipe to refresh spinner listener.
1680         swipeToRefreshSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1681             @Override
1682             public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1683                 // Update the icon and the visibility of `nightModeTextView`.  Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
1684                 switch (position) {
1685                     case DomainsDatabaseHelper.SYSTEM_DEFAULT:
1686                         if (defaultSwipeToRefresh) {  // Swipe to refresh enabled by default.
1687                             // Set the icon according to the theme.
1688                             if (darkTheme) {
1689                                 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_enabled_dark));
1690                             } else {
1691                                 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_enabled_light));
1692                             }
1693                         } else {  // Swipe to refresh disabled by default.
1694                             // Set the icon according to the theme.
1695                             if (darkTheme) {
1696                                 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_disabled_dark));
1697                             } else {
1698                                 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_disabled_light));
1699                             }
1700                         }
1701
1702                         // Show the swipe to refresh TextView.
1703                         swipeToRefreshTextView.setVisibility(View.VISIBLE);
1704                         break;
1705
1706                     case DomainsDatabaseHelper.ENABLED:
1707                         // Set the icon according to the theme.
1708                         if (darkTheme) {
1709                             swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_enabled_dark));
1710                         } else {
1711                             swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_enabled_light));
1712                         }
1713
1714                         // Hide the swipe to refresh TextView.
1715                         swipeToRefreshTextView.setVisibility(View.GONE);
1716                         break;
1717
1718                     case DomainsDatabaseHelper.DISABLED:
1719                         // Set the icon according to the theme.
1720                         if (darkTheme) {
1721                             swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_disabled_dark));
1722                         } else {
1723                             swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_disabled_light));
1724                         }
1725
1726                         // Hide the swipe to refresh TextView.
1727                         swipeToRefreshTextView.setVisibility(View.GONE);
1728                 }
1729             }
1730
1731             @Override
1732             public void onNothingSelected(AdapterView<?> parent) {
1733                 // Do nothing.
1734             }
1735         });
1736
1737         // Set the night mode spinner listener.
1738         nightModeSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1739             @Override
1740             public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1741                 // Update the icon and the visibility of `nightModeTextView`.  Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
1742                 switch (position) {
1743                     case DomainsDatabaseHelper.SYSTEM_DEFAULT:
1744                         if (defaultNightMode) {  // Night mode enabled by default.
1745                             // Set the icon according to the theme.
1746                             if (darkTheme) {
1747                                 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_dark));
1748                             } else {
1749                                 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_light));
1750                             }
1751                         } else {  // Night mode disabled by default.
1752                             // Set the icon according to the theme.
1753                             if (darkTheme) {
1754                                 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_dark));
1755                             } else {
1756                                 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_light));
1757                             }
1758                         }
1759
1760                         // Show the night mode TextView.
1761                         nightModeTextView.setVisibility(View.VISIBLE);
1762                         break;
1763
1764                     case DomainsDatabaseHelper.ENABLED:
1765                         // Set the icon according to the theme.
1766                         if (darkTheme) {
1767                             nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_dark));
1768                         } else {
1769                             nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_light));
1770                         }
1771
1772                         // Hide `nightModeTextView`.
1773                         nightModeTextView.setVisibility(View.GONE);
1774                         break;
1775
1776                     case DomainsDatabaseHelper.DISABLED:
1777                         // Set the icon according to the theme.
1778                         if (darkTheme) {
1779                             nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_dark));
1780                         } else {
1781                             nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_light));
1782                         }
1783
1784                         // Hide `nightModeTextView`.
1785                         nightModeTextView.setVisibility(View.GONE);
1786                         break;
1787                 }
1788
1789                 // Create a boolean to store the current night mode setting.
1790                 boolean currentNightModeEnabled = (position == DomainsDatabaseHelper.ENABLED) || ((position == DomainsDatabaseHelper.SYSTEM_DEFAULT) && defaultNightMode);
1791
1792                 // Disable the JavaScript switch if night mode is enabled.
1793                 if (currentNightModeEnabled) {
1794                     javaScriptSwitch.setEnabled(false);
1795                 } else {
1796                     javaScriptSwitch.setEnabled(true);
1797                 }
1798
1799                 // Update the JavaScript icon.
1800                 if ((javaScriptInt == 1) || currentNightModeEnabled) {
1801                     javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.javascript_enabled));
1802                 } else {
1803                     javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.privacy_mode));
1804                 }
1805
1806                 // Update the DOM storage status.
1807                 if ((javaScriptInt == 1) || currentNightModeEnabled) {  // JavaScript is enabled.
1808                     // Enable the DOM storage `Switch`.
1809                     domStorageSwitch.setEnabled(true);
1810
1811                     // Set the DOM storage status.  Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
1812                     if (domStorageInt == 1) {  // Both JavaScript and DOM storage are enabled.
1813                         domStorageSwitch.setChecked(true);
1814                         domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_enabled));
1815                     } else {  // JavaScript is enabled but DOM storage is disabled.
1816                         // Set the DOM storage switch to off.
1817                         domStorageSwitch.setChecked(false);
1818
1819                         // Set the icon according to the theme.
1820                         if (darkTheme) {
1821                             domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_dark));
1822                         } else {
1823                             domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_light));
1824                         }
1825                     }
1826                 } else {  // JavaScript is disabled.
1827                     // Disable the DOM storage `Switch`.
1828                     domStorageSwitch.setEnabled(false);
1829
1830                     // Set the checked status of DOM storage.
1831                     if (domStorageInt == 1) {  // DOM storage is enabled but JavaScript is disabled.
1832                         domStorageSwitch.setChecked(true);
1833                     } else {  // Both JavaScript and DOM storage are disabled.
1834                         domStorageSwitch.setChecked(false);
1835                     }
1836
1837                     // Set the icon according to the theme.
1838                     if (darkTheme) {
1839                         domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_dark));
1840                     } else {
1841                         domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_light));
1842                     }
1843                 }
1844             }
1845
1846             @Override
1847             public void onNothingSelected(AdapterView<?> parent) {
1848                 // Do nothing.
1849             }
1850         });
1851
1852         // Set the wide viewport spinner listener.
1853         wideViewportSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1854             @Override
1855             public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1856                 // Update the icon and the visibility of the wide viewport text view.
1857                 switch (position) {
1858                     case DomainsDatabaseHelper.SYSTEM_DEFAULT:
1859                         if (defaultWideViewport) {  // Wide viewport is enabled by default.
1860                             // Set the icon according to the theme.
1861                             if (darkTheme) {
1862                                 wideViewportImageView.setImageDrawable(resources.getDrawable(R.drawable.wide_viewport_enabled_dark));
1863                             } else {
1864                                 wideViewportImageView.setImageDrawable(resources.getDrawable(R.drawable.wide_viewport_enabled_light));
1865                             }
1866                         } else {  // Wide viewport is disabled by default.
1867                             if (darkTheme) {
1868                                 wideViewportImageView.setImageDrawable(resources.getDrawable(R.drawable.wide_viewport_disabled_dark));
1869                             } else {
1870                                 wideViewportImageView.setImageDrawable(resources.getDrawable(R.drawable.wide_viewport_disabled_light));
1871                             }
1872                         }
1873
1874                         // Show the wide viewport text view.
1875                         wideViewportTextView.setVisibility(View.VISIBLE);
1876                         break;
1877
1878                     case DomainsDatabaseHelper.ENABLED:
1879                         // Set the icon according to the theme.
1880                         if (darkTheme) {
1881                             wideViewportImageView.setImageDrawable(resources.getDrawable(R.drawable.wide_viewport_enabled_dark));
1882                         } else {
1883                             wideViewportImageView.setImageDrawable(resources.getDrawable(R.drawable.wide_viewport_enabled_light));
1884                         }
1885
1886                         // Hide the wide viewport text view.
1887                         wideViewportTextView.setVisibility(View.GONE);
1888                         break;
1889
1890                     case DomainsDatabaseHelper.DISABLED:
1891                         // Set the icon according to the theme.
1892                         if (darkTheme) {
1893                             wideViewportImageView.setImageDrawable(resources.getDrawable(R.drawable.wide_viewport_disabled_dark));
1894                         } else {
1895                             wideViewportImageView.setImageDrawable(resources.getDrawable(R.drawable.wide_viewport_disabled_light));
1896                         }
1897
1898                         // Hid ethe wide viewport text view.
1899                         wideViewportTextView.setVisibility(View.GONE);
1900                         break;
1901                 }
1902             }
1903
1904             @Override
1905             public void onNothingSelected(AdapterView<?> parent) {
1906                 // Do nothing.
1907             }
1908         });
1909
1910         // Set the display webpage images spinner listener.
1911         displayWebpageImagesSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1912             @Override
1913             public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1914                 // Update the icon and the visibility of the display images text view.
1915                 switch (position) {
1916                     case DomainsDatabaseHelper.SYSTEM_DEFAULT:
1917                         if (defaultDisplayWebpageImages) {  // Display webpage images is enabled by default.
1918                             // Set the icon according to the theme.
1919                             if (darkTheme) {
1920                                 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_dark));
1921                             } else {
1922                                 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_light));
1923                             }
1924                         } else {  // Display webpage images is disabled by default.
1925                             // Set the icon according to the theme.
1926                             if (darkTheme) {
1927                                 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_dark));
1928                             } else {
1929                                 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_light));
1930                             }
1931                         }
1932
1933                         // Show the display images text view.
1934                         displayImagesTextView.setVisibility(View.VISIBLE);
1935                         break;
1936
1937                     case DomainsDatabaseHelper.ENABLED:
1938                         // Set the icon according to the theme.
1939                         if (darkTheme) {
1940                             displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_dark));
1941                         } else {
1942                             displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_light));
1943                         }
1944
1945                         // Hide the display images text view.
1946                         displayImagesTextView.setVisibility(View.GONE);
1947                         break;
1948
1949                     case DomainsDatabaseHelper.DISABLED:
1950                         // Set the icon according to the theme.
1951                         if (darkTheme) {
1952                             displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_dark));
1953                         } else {
1954                             displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_light));
1955                         }
1956
1957                         // Hide the display images text view.
1958                         displayImagesTextView.setVisibility(View.GONE);
1959                         break;
1960                 }
1961             }
1962
1963             @Override
1964             public void onNothingSelected(AdapterView<?> parent) {
1965                 // Do nothing.
1966             }
1967         });
1968         
1969         // Set the pinned SSL certificate switch listener.
1970         pinnedSslCertificateSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1971             // Update the icon.
1972             if (isChecked) {  // SSL certificate pinning is enabled.
1973                 // Set the icon according to the theme.
1974                 if (darkTheme) {
1975                     pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_dark));
1976                 } else {
1977                     pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_light));
1978                 }
1979
1980                 // Update the visibility of the saved SSL certificate.
1981                 if (savedSslIssuedToCNameString == null) {
1982                     savedSslCardView.setVisibility(View.GONE);
1983                 } else {
1984                     savedSslCardView.setVisibility(View.VISIBLE);
1985                 }
1986
1987                 // Update the visibility of the current website SSL certificate.
1988                 if (DomainsActivity.sslIssuedToCName == null) {
1989                     // Hide the SSL certificate.
1990                     currentSslCardView.setVisibility(View.GONE);
1991
1992                     // Show the instruction.
1993                     noCurrentWebsiteCertificateTextView.setVisibility(View.VISIBLE);
1994                 } else {
1995                     // Show the SSL certificate.
1996                     currentSslCardView.setVisibility(View.VISIBLE);
1997
1998                     // Hide the instruction.
1999                     noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
2000                 }
2001
2002                 // Set the status of the radio buttons.
2003                 if (savedSslCardView.getVisibility() == View.VISIBLE) {  // The saved SSL certificate is displayed.
2004                     // Check the saved SSL certificate radio button.
2005                     savedSslCertificateRadioButton.setChecked(true);
2006
2007                     // Uncheck the current website SSL certificate radio button.
2008                     currentWebsiteCertificateRadioButton.setChecked(false);
2009
2010                     // Set the background of the saved SSL certificate linear layout to be transparent.
2011                     savedSslCertificateLinearLayout.setBackgroundResource(R.color.transparent);
2012
2013                     // Darken the background of the current website SSL certificate linear layout according to the theme.
2014                     if (darkTheme) {
2015                         currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2016                     } else {
2017                         currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2018                     }
2019
2020                     // Scroll to the current website SSL certificate card.
2021                     savedSslCardView.getParent().requestChildFocus(savedSslCardView, savedSslCardView);
2022                 } else if (currentSslCardView.getVisibility() == View.VISIBLE) {  // The saved SSL certificate is hidden but the current website SSL certificate is visible.
2023                     // Check the current website SSL certificate radio button.
2024                     currentWebsiteCertificateRadioButton.setChecked(true);
2025
2026                     // Uncheck the saved SSL certificate radio button.
2027                     savedSslCertificateRadioButton.setChecked(false);
2028
2029                     // Set the background of the current website SSL certificate linear layout to be transparent.
2030                     currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.transparent);
2031
2032                     // Darken the background of the saved SSL certificate linear layout according to the theme.
2033                     if (darkTheme) {
2034                         savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2035                     } else {
2036                         savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2037                     }
2038
2039                     // Scroll to the current website SSL certificate card.
2040                     currentSslCardView.getParent().requestChildFocus(currentSslCardView, currentSslCardView);
2041                 } else {  // Neither SSL certificate is visible.
2042                     // Uncheck both radio buttons.
2043                     savedSslCertificateRadioButton.setChecked(false);
2044                     currentWebsiteCertificateRadioButton.setChecked(false);
2045
2046                     // Scroll to the current website SSL certificate card.
2047                     noCurrentWebsiteCertificateTextView.getParent().requestChildFocus(noCurrentWebsiteCertificateTextView, noCurrentWebsiteCertificateTextView);
2048                 }
2049             } else {  // SSL certificate pinning is disabled.
2050                 // Set the icon according to the theme.
2051                 if (darkTheme) {
2052                     pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_dark));
2053                 } else {
2054                     pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_light));
2055                 }
2056
2057                 // Hide the SSl certificates and instructions.
2058                 savedSslCardView.setVisibility(View.GONE);
2059                 currentSslCardView.setVisibility(View.GONE);
2060                 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
2061
2062                 // Uncheck the radio buttons.
2063                 savedSslCertificateRadioButton.setChecked(false);
2064                 currentWebsiteCertificateRadioButton.setChecked(false);
2065             }
2066         });
2067
2068         savedSslCardView.setOnClickListener((View view) -> {
2069             // Check the saved SSL certificate radio button.
2070             savedSslCertificateRadioButton.setChecked(true);
2071
2072             // Uncheck the current website SSL certificate radio button.
2073             currentWebsiteCertificateRadioButton.setChecked(false);
2074
2075             // Set the background of the saved SSL certificate linear layout to be transparent.
2076             savedSslCertificateLinearLayout.setBackgroundResource(R.color.transparent);
2077
2078             // Darken the background of the current website SSL certificate linear layout according to the theme.
2079             if (darkTheme) {
2080                 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2081             } else {
2082                 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2083             }
2084         });
2085
2086         savedSslCertificateRadioButton.setOnClickListener((View view) -> {
2087             // Check the saved SSL certificate radio button.
2088             savedSslCertificateRadioButton.setChecked(true);
2089
2090             // Uncheck the current website SSL certificate radio button.
2091             currentWebsiteCertificateRadioButton.setChecked(false);
2092
2093             // Set the background of the saved SSL certificate linear layout to be transparent.
2094             savedSslCertificateLinearLayout.setBackgroundResource(R.color.transparent);
2095
2096             // Darken the background of the current website SSL certificate linear layout according to the theme.
2097             if (darkTheme) {
2098                 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2099             } else {
2100                 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2101             }
2102         });
2103
2104         currentSslCardView.setOnClickListener((View view) -> {
2105             // Check the current website SSL certificate radio button.
2106             currentWebsiteCertificateRadioButton.setChecked(true);
2107
2108             // Uncheck the saved SSL certificate radio button.
2109             savedSslCertificateRadioButton.setChecked(false);
2110
2111             // Set the background of the current website SSL certificate linear layout to be transparent.
2112             currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.transparent);
2113
2114             // Darken the background of the saved SSL certificate linear layout according to the theme.
2115             if (darkTheme) {
2116                 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2117             } else {
2118                 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2119             }
2120         });
2121
2122         currentWebsiteCertificateRadioButton.setOnClickListener((View view) -> {
2123             // Check the current website SSL certificate radio button.
2124             currentWebsiteCertificateRadioButton.setChecked(true);
2125
2126             // Uncheck the saved SSL certificate radio button.
2127             savedSslCertificateRadioButton.setChecked(false);
2128
2129             // Set the background of the current website SSL certificate linear layout to be transparent.
2130             currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.transparent);
2131
2132             // Darken the background of the saved SSL certificate linear layout according to the theme.
2133             if (darkTheme) {
2134                 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2135             } else {
2136                 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2137             }
2138         });
2139
2140         // Set the pinned IP addresses switch listener.
2141         pinnedIpAddressesSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
2142             // Update the icon.
2143             if (isChecked) {  // IP addresses pinning is enabled.
2144                 // Set the icon according to the theme.
2145                 if (darkTheme) {
2146                     pinnedIpAddressesImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_dark));
2147                 } else {
2148                     pinnedIpAddressesImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_light));
2149                 }
2150
2151                 // Update the visibility of the saved IP addresses card view.
2152                 if (savedIpAddresses == null) {  // There are no saved IP addresses.
2153                     savedIpAddressesCardView.setVisibility(View.GONE);
2154                 } else {  // There are saved IP addresses.
2155                     savedIpAddressesCardView.setVisibility(View.VISIBLE);
2156                 }
2157
2158                 // Show the current IP addresses card view.
2159                 currentIpAddressesCardView.setVisibility(View.VISIBLE);
2160
2161                 // Set the status of the radio buttons.
2162                 if (savedIpAddressesCardView.getVisibility() == View.VISIBLE) {  // The saved IP addresses are visible.
2163                     // Check the saved IP addresses radio button.
2164                     savedIpAddressesRadioButton.setChecked(true);
2165
2166                     // Uncheck the current IP addresses radio button.
2167                     currentIpAddressesRadioButton.setChecked(false);
2168
2169                     // Set the background of the saved IP addresses linear layout to be transparent.
2170                     savedSslCertificateLinearLayout.setBackgroundResource(R.color.transparent);
2171
2172                     // Darken the background of the current IP addresses linear layout according to the theme.
2173                     if (darkTheme) {
2174                         currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2175                     } else {
2176                         currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2177                     }
2178                 } else {  // The saved IP addresses are not visible.
2179                     // Check the current IP addresses radio button.
2180                     currentIpAddressesRadioButton.setChecked(true);
2181
2182                     // Uncheck the saved IP addresses radio button.
2183                     savedIpAddressesRadioButton.setChecked(false);
2184
2185                     // Set the background of the current IP addresses linear layout to be transparent.
2186                     currentIpAddressesLinearLayout.setBackgroundResource(R.color.transparent);
2187
2188                     // Darken the background of the saved IP addresses linear layout according to the theme.
2189                     if (darkTheme) {
2190                         savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2191                     } else {
2192                         savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2193                     }
2194                 }
2195
2196                 // Scroll to the bottom of the card views.
2197                 currentIpAddressesCardView.getParent().requestChildFocus(currentIpAddressesCardView, currentIpAddressesCardView);
2198             } else {  // IP addresses pinning is disabled.
2199                 // Set the icon according to the theme.
2200                 if (darkTheme) {
2201                     pinnedIpAddressesImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_dark));
2202                 } else {
2203                     pinnedIpAddressesImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_light));
2204                 }
2205
2206                 // Hide the IP addresses card views.
2207                 savedIpAddressesCardView.setVisibility(View.GONE);
2208                 currentIpAddressesCardView.setVisibility(View.GONE);
2209
2210                 // Uncheck the radio buttons.
2211                 savedIpAddressesRadioButton.setChecked(false);
2212                 currentIpAddressesRadioButton.setChecked(false);
2213             }
2214         });
2215
2216         savedIpAddressesCardView.setOnClickListener((View view) -> {
2217             // Check the saved IP addresses radio button.
2218             savedIpAddressesRadioButton.setChecked(true);
2219
2220             // Uncheck the current website IP addresses radio button.
2221             currentIpAddressesRadioButton.setChecked(false);
2222
2223             // Set the background of the saved IP addresses linear layout to be transparent.
2224             savedIpAddressesLinearLayout.setBackgroundResource(R.color.transparent);
2225
2226             // Darken the background of the current IP addresses linear layout according to the theme.
2227             if (darkTheme) {
2228                 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2229             } else {
2230                 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2231             }
2232         });
2233
2234         savedIpAddressesRadioButton.setOnClickListener((View view) -> {
2235             // Check the saved IP addresses radio button.
2236             savedIpAddressesRadioButton.setChecked(true);
2237
2238             // Uncheck the current website IP addresses radio button.
2239             currentIpAddressesRadioButton.setChecked(false);
2240
2241             // Set the background of the saved IP addresses linear layout to be transparent.
2242             savedIpAddressesLinearLayout.setBackgroundResource(R.color.transparent);
2243
2244             // Darken the background of the current IP addresses linear layout according to the theme.
2245             if (darkTheme) {
2246                 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2247             } else {
2248                 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2249             }
2250         });
2251
2252         currentIpAddressesCardView.setOnClickListener((View view) -> {
2253             // Check the current IP addresses radio button.
2254             currentIpAddressesRadioButton.setChecked(true);
2255
2256             // Uncheck the saved IP addresses radio button.
2257             savedIpAddressesRadioButton.setChecked(false);
2258
2259             // Set the background of the current IP addresses linear layout to be transparent.
2260             currentIpAddressesLinearLayout.setBackgroundResource(R.color.transparent);
2261
2262             // Darken the background of the saved IP addresses linear layout according to the theme.
2263             if (darkTheme) {
2264                 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2265             } else {
2266                 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2267             }
2268         });
2269
2270         currentIpAddressesRadioButton.setOnClickListener((View view) -> {
2271             // Check the current IP addresses radio button.
2272             currentIpAddressesRadioButton.setChecked(true);
2273
2274             // Uncheck the saved IP addresses radio button.
2275             savedIpAddressesRadioButton.setChecked(false);
2276
2277             // Set the background of the current IP addresses linear layout to be transparent.
2278             currentIpAddressesLinearLayout.setBackgroundResource(R.color.transparent);
2279
2280             // Darken the background of the saved IP addresses linear layout according to the theme.
2281             if (darkTheme) {
2282                 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2283             } else {
2284                 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2285             }
2286         });
2287
2288         return domainSettingsView;
2289     }
2290
2291     private boolean checkDomainNameAgainstCertificate(String domainName, String certificateCommonName) {
2292         // Initialize `domainNamesMatch`.
2293         boolean domainNamesMatch = false;
2294
2295         // Check various wildcard permutations if `domainName` and `certificateCommonName` are not empty.
2296         // `noinspection ConstantCondition` removes Android Studio's incorrect lint warning that `domainName` can never be `null`.
2297         if ((domainName != null) && (certificateCommonName != null)) {
2298             // Check if the domains match.
2299             if (domainName.equals(certificateCommonName)) {
2300                 domainNamesMatch = true;
2301             }
2302
2303             // If `domainName` starts with a wildcard, check the base domain against all the subdomains of `certificateCommonName`.
2304             if (!domainNamesMatch && domainName.startsWith("*.") && (domainName.length() > 2)) {
2305                 // Remove the initial `*.`.
2306                 String baseDomainName = domainName.substring(2);
2307
2308                 // Setup a copy of `certificateCommonName` to test subdomains.
2309                 String certificateCommonNameSubdomain = certificateCommonName;
2310
2311                 // Check all the subdomains in `certificateCommonNameSubdomain` against `baseDomainName`.
2312                 while (!domainNamesMatch && certificateCommonNameSubdomain.contains(".")) {  // Stop checking if we know that `domainNamesMatch` is `true` or if we run out of  `.`.
2313                     // Test the `certificateCommonNameSubdomain` against `baseDomainName`.
2314                     if (certificateCommonNameSubdomain.equals(baseDomainName)) {
2315                         domainNamesMatch = true;
2316                     }
2317
2318                     // Strip out the lowest subdomain of `certificateCommonNameSubdomain`.
2319                     try {
2320                         certificateCommonNameSubdomain = certificateCommonNameSubdomain.substring(certificateCommonNameSubdomain.indexOf(".") + 1);
2321                     } catch (IndexOutOfBoundsException e) {  // `certificateCommonNameSubdomain` ends with `.`.
2322                         certificateCommonNameSubdomain = "";
2323                     }
2324                 }
2325             }
2326
2327             // If `certificateCommonName` starts with a wildcard, check the base common name against all the subdomains of `domainName`.
2328             if (!domainNamesMatch && certificateCommonName.startsWith("*.") && (certificateCommonName.length() > 2)) {
2329                 // Remove the initial `*.`.
2330                 String baseCertificateCommonName = certificateCommonName.substring(2);
2331
2332                 // Setup a copy of `domainName` to test subdomains.
2333                 String domainNameSubdomain = domainName;
2334
2335                 // Check all the subdomains in `domainNameSubdomain` against `baseCertificateCommonName`.
2336                 while (!domainNamesMatch && domainNameSubdomain.contains(".") && (domainNameSubdomain.length() > 2)) {
2337                     // Test the `domainNameSubdomain` against `baseCertificateCommonName`.
2338                     if (domainNameSubdomain.equals(baseCertificateCommonName)) {
2339                         domainNamesMatch = true;
2340                     }
2341
2342                     // Strip out the lowest subdomain of `domainNameSubdomain`.
2343                     try {
2344                         domainNameSubdomain = domainNameSubdomain.substring(domainNameSubdomain.indexOf(".") + 1);
2345                     } catch (IndexOutOfBoundsException e) { // `domainNameSubdomain` ends with `.`.
2346                         domainNameSubdomain = "";
2347                     }
2348                 }
2349             }
2350
2351             // If both names start with a wildcard, check if the root of one contains the root of the other.
2352             if (!domainNamesMatch && domainName.startsWith("*.") && (domainName.length() > 2) && certificateCommonName.startsWith("*.") && (certificateCommonName.length() > 2)) {
2353                 // Remove the wildcards.
2354                 String rootDomainName = domainName.substring(2);
2355                 String rootCertificateCommonName = certificateCommonName.substring(2);
2356
2357                 // Check if one name ends with the contents of the other.  If so, there will be overlap in the their wildcard subdomains.
2358                 if (rootDomainName.endsWith(rootCertificateCommonName) || rootCertificateCommonName.endsWith(rootDomainName)) {
2359                     domainNamesMatch = true;
2360                 }
2361             }
2362         }
2363
2364         return domainNamesMatch;
2365     }
2366 }