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