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