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