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