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