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