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