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