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