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