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