2 * Copyright © 2017-2018 Soren Stoutner <soren@stoutner.com>.
4 * This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
6 * Privacy Browser is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * Privacy Browser is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with Privacy Browser. If not, see <http://www.gnu.org/licenses/>.
20 package com.stoutner.privacybrowser.fragments;
22 import android.annotation.SuppressLint;
23 import android.content.Context;
24 import android.content.SharedPreferences;
25 import android.content.res.Resources;
26 import android.database.Cursor;
27 import android.net.http.SslCertificate;
28 import android.os.Build;
29 import android.os.Bundle;
30 // We have to use `android.support.v4.app.Fragment` until minimum API >= 23. Otherwise we cannot call `getContext()`.
31 import android.preference.PreferenceManager;
32 import android.support.annotation.NonNull;
33 import android.support.v4.app.Fragment;
34 import android.text.Editable;
35 import android.text.SpannableStringBuilder;
36 import android.text.Spanned;
37 import android.text.TextWatcher;
38 import android.text.style.ForegroundColorSpan;
39 import android.view.LayoutInflater;
40 import android.view.View;
41 import android.view.ViewGroup;
42 import android.webkit.WebView;
43 import android.widget.AdapterView;
44 import android.widget.ArrayAdapter;
45 import android.widget.CompoundButton;
46 import android.widget.EditText;
47 import android.widget.ImageView;
48 import android.widget.LinearLayout;
49 import android.widget.RadioButton;
50 import android.widget.Spinner;
51 import android.widget.Switch;
52 import android.widget.TextView;
54 import com.stoutner.privacybrowser.R;
55 import com.stoutner.privacybrowser.activities.MainWebViewActivity;
56 import com.stoutner.privacybrowser.helpers.DomainsDatabaseHelper;
58 import java.text.DateFormat;
59 import java.util.Calendar;
60 import java.util.Date;
62 public class DomainSettingsFragment extends Fragment {
63 // `DATABASE_ID` is used by activities calling this fragment.
64 public static final String DATABASE_ID = "database_id";
66 // `databaseId` is public static so it can be accessed from `DomainsActivity`. It is also used in `onCreate()` and `onCreateView()`.
67 public static int databaseId;
70 public void onCreate(Bundle savedInstanceState) {
71 super.onCreate(savedInstanceState);
73 // Remove the lint warning that `getArguments` might be null.
74 assert getArguments() != null;
76 // Store the database id in `databaseId`.
77 databaseId = getArguments().getInt(DATABASE_ID);
80 // The deprecated `getDrawable()` must be used until the minimum API >= 21.
81 @SuppressWarnings("deprecation")
83 public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
84 // Inflate `domain_settings_fragment`. `false` does not attach it to the root `container`.
85 View domainSettingsView = inflater.inflate(R.layout.domain_settings_fragment, container, false);
87 // Get a handle for the `Context` and the `Resources`.
88 Context context = getContext();
89 final Resources resources = getResources();
91 // Get a handle for the shared preference.
92 SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
94 // Store the default settings.
95 final String defaultUserAgentName = sharedPreferences.getString("user_agent", "Privacy Browser");
96 final String defaultCustomUserAgentString = sharedPreferences.getString("custom_user_agent", "PrivacyBrowser/1.0");
97 String defaultFontSizeString = sharedPreferences.getString("default_font_size", "100");
98 boolean defaultSwipeToRefreshBoolean = sharedPreferences.getBoolean("swipe_to_refresh", true);
99 final boolean defaultNightModeBoolean = sharedPreferences.getBoolean("night_mode", false);
100 final boolean defaultDisplayWebpageImagesBoolean = sharedPreferences.getBoolean("display_website_images", true);
102 // Get handles for the views in the fragment.
103 final EditText domainNameEditText = domainSettingsView.findViewById(R.id.domain_settings_name_edittext);
104 final Switch javaScriptEnabledSwitch = domainSettingsView.findViewById(R.id.domain_settings_javascript_switch);
105 final ImageView javaScriptImageView = domainSettingsView.findViewById(R.id.domain_settings_javascript_imageview);
106 Switch firstPartyCookiesEnabledSwitch = domainSettingsView.findViewById(R.id.domain_settings_first_party_cookies_switch);
107 final ImageView firstPartyCookiesImageView = domainSettingsView.findViewById(R.id.domain_settings_first_party_cookies_imageview);
108 LinearLayout thirdPartyCookiesLinearLayout = domainSettingsView.findViewById(R.id.domain_settings_third_party_cookies_linearlayout);
109 final Switch thirdPartyCookiesEnabledSwitch = domainSettingsView.findViewById(R.id.domain_settings_third_party_cookies_switch);
110 final ImageView thirdPartyCookiesImageView = domainSettingsView.findViewById(R.id.domain_settings_third_party_cookies_imageview);
111 final Switch domStorageEnabledSwitch = domainSettingsView.findViewById(R.id.domain_settings_dom_storage_switch);
112 final ImageView domStorageImageView = domainSettingsView.findViewById(R.id.domain_settings_dom_storage_imageview);
113 Switch formDataEnabledSwitch = domainSettingsView.findViewById(R.id.domain_settings_form_data_switch); // The form data views can be remove once the minimum API >= 26.
114 final ImageView formDataImageView = domainSettingsView.findViewById(R.id.domain_settings_form_data_imageview); // The form data views can be remove once the minimum API >= 26.
115 Switch easyListSwitch = domainSettingsView.findViewById(R.id.domain_settings_easylist_switch);
116 ImageView easyListImageView = domainSettingsView.findViewById(R.id.domain_settings_easylist_imageview);
117 Switch easyPrivacySwitch = domainSettingsView.findViewById(R.id.domain_settings_easyprivacy_switch);
118 ImageView easyPrivacyImageView = domainSettingsView.findViewById(R.id.domain_settings_easyprivacy_imageview);
119 Switch fanboysAnnoyanceListSwitch = domainSettingsView.findViewById(R.id.domain_settings_fanboys_annoyance_list_switch);
120 ImageView fanboysAnnoyanceListImageView = domainSettingsView.findViewById(R.id.domain_settings_fanboys_annoyance_list_imageview);
121 Switch fanboysSocialBlockingListSwitch = domainSettingsView.findViewById(R.id.domain_settings_fanboys_social_blocking_list_switch);
122 ImageView fanboysSocialBlockingListImageView = domainSettingsView.findViewById(R.id.domain_settings_fanboys_social_blocking_list_imageview);
123 final Spinner userAgentSpinner = domainSettingsView.findViewById(R.id.domain_settings_user_agent_spinner);
124 final TextView userAgentTextView = domainSettingsView.findViewById(R.id.domain_settings_user_agent_textview);
125 final EditText customUserAgentEditText = domainSettingsView.findViewById(R.id.domain_settings_custom_user_agent_edittext);
126 final Spinner fontSizeSpinner = domainSettingsView.findViewById(R.id.domain_settings_font_size_spinner);
127 final TextView fontSizeTextView = domainSettingsView.findViewById(R.id.domain_settings_font_size_textview);
128 final ImageView swipeToRefreshImageView = domainSettingsView.findViewById(R.id.domain_settings_swipe_to_refresh_imageview);
129 final Spinner swipeToRefreshSpinner = domainSettingsView.findViewById(R.id.domain_settings_swipe_to_refresh_spinner);
130 final TextView swipeToRefreshTextView = domainSettingsView.findViewById(R.id.domain_settings_swipe_to_refresh_textview);
131 final ImageView nightModeImageView = domainSettingsView.findViewById(R.id.domain_settings_night_mode_imageview);
132 final Spinner nightModeSpinner = domainSettingsView.findViewById(R.id.domain_settings_night_mode_spinner);
133 final TextView nightModeTextView = domainSettingsView.findViewById(R.id.domain_settings_night_mode_textview);
134 final ImageView displayWebpageImagesImageView = domainSettingsView.findViewById(R.id.domain_settings_display_webpage_images_imageview);
135 final Spinner displayWebpageImagesSpinner = domainSettingsView.findViewById(R.id.domain_settings_display_webpage_images_spinner);
136 final TextView displayImagesTextView = domainSettingsView.findViewById(R.id.domain_settings_display_webpage_images_textview);
137 final ImageView pinnedSslCertificateImageView = domainSettingsView.findViewById(R.id.domain_settings_pinned_ssl_certificate_imageview);
138 Switch pinnedSslCertificateSwitch = domainSettingsView.findViewById(R.id.domain_settings_pinned_ssl_certificate_switch);
139 final LinearLayout savedSslCertificateLinearLayout = domainSettingsView.findViewById(R.id.saved_ssl_certificate_linearlayout);
140 final RadioButton savedSslCertificateRadioButton = domainSettingsView.findViewById(R.id.saved_ssl_certificate_radiobutton);
141 final TextView savedSslCertificateIssuedToCNameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_to_cname);
142 TextView savedSslCertificateIssuedToONameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_to_oname);
143 TextView savedSslCertificateIssuedToUNameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_to_uname);
144 TextView savedSslCertificateIssuedByCNameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_by_cname);
145 TextView savedSslCertificateIssuedByONameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_by_oname);
146 TextView savedSslCertificateIssuedByUNameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_by_uname);
147 TextView savedSslCertificateStartDateTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_start_date);
148 TextView savedSslCertificateEndDateTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_end_date);
149 final LinearLayout currentWebsiteCertificateLinearLayout = domainSettingsView.findViewById(R.id.current_website_certificate_linearlayout);
150 final RadioButton currentWebsiteCertificateRadioButton = domainSettingsView.findViewById(R.id.current_website_certificate_radiobutton);
151 final TextView currentWebsiteCertificateIssuedToCNameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_to_cname);
152 TextView currentWebsiteCertificateIssuedToONameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_to_oname);
153 TextView currentWebsiteCertificateIssuedToUNameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_to_uname);
154 TextView currentWebsiteCertificateIssuedByCNameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_by_cname);
155 TextView currentWebsiteCertificateIssuedByONameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_by_oname);
156 TextView currentWebsiteCertificateIssuedByUNameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_by_uname);
157 TextView currentWebsiteCertificateStartDateTextView = domainSettingsView.findViewById(R.id.current_website_certificate_start_date);
158 TextView currentWebsiteCertificateEndDateTextView = domainSettingsView.findViewById(R.id.current_website_certificate_end_date);
159 final TextView noCurrentWebsiteCertificateTextView = domainSettingsView.findViewById(R.id.no_current_website_certificate);
161 // Setup the SSL certificate labels.
162 final String cNameLabel = getString(R.string.common_name) + " ";
163 String oNameLabel = getString(R.string.organization) + " ";
164 String uNameLabel = getString(R.string.organizational_unit) + " ";
165 String startDateLabel = getString(R.string.start_date) + " ";
166 String endDateLabel = getString(R.string.end_date) + " ";
168 // Get the current website SSL certificate
169 final SslCertificate currentWebsiteSslCertificate = MainWebViewActivity.sslCertificate;
171 // Initialize the database handler. The `0` specifies the database version, but that is ignored and set instead using a constant in `DomainsDatabaseHelper`.
172 DomainsDatabaseHelper domainsDatabaseHelper = new DomainsDatabaseHelper(context, null, null, 0);
174 // Get the database `Cursor` for this ID and move it to the first row.
175 Cursor domainCursor = domainsDatabaseHelper.getCursorForId(databaseId);
176 domainCursor.moveToFirst();
178 // Save the `Cursor` entries as variables.
179 String domainNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.DOMAIN_NAME));
180 final int javaScriptEnabledInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_JAVASCRIPT));
181 int firstPartyCookiesEnabledInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FIRST_PARTY_COOKIES));
182 int thirdPartyCookiesEnabledInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_THIRD_PARTY_COOKIES));
183 final int domStorageEnabledInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_DOM_STORAGE));
184 int formDataEnabledInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FORM_DATA)); // Form data can be remove once the minimum API >= 26.
185 int easyListEnabledInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_EASYLIST));
186 int easyPrivacyEnabledInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_EASYPRIVACY));
187 int fanboysAnnoyanceListInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FANBOYS_ANNOYANCE_LIST));
188 int fanboysSocialBlockingListInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FANBOYS_SOCIAL_BLOCKING_LIST));
189 final String currentUserAgentName = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.USER_AGENT));
190 int fontSizeInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.FONT_SIZE));
191 int swipeToRefreshInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.SWIPE_TO_REFRESH));
192 int nightModeInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.NIGHT_MODE));
193 int displayImagesInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.DISPLAY_IMAGES));
194 int pinnedSslCertificateInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.PINNED_SSL_CERTIFICATE));
195 final String savedSslCertificateIssuedToCNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_TO_COMMON_NAME));
196 String savedSslCertificateIssuedToONameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_TO_ORGANIZATION));
197 String savedSslCertificateIssuedToUNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_TO_ORGANIZATIONAL_UNIT));
198 String savedSslCertificateIssuedByCNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_BY_COMMON_NAME));
199 String savedSslCertificateIssuedByONameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_BY_ORGANIZATION));
200 String savedSslCertificateIssuedByUNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_BY_ORGANIZATIONAL_UNIT));
202 // Initialize the saved SSL certificate date variables.
203 Date savedSslCertificateStartDate = null;
204 Date savedSslCertificateEndDate = null;
206 // Only get the saved SSL certificate dates from the cursor if they are not set to `0`.
207 if (domainCursor.getLong(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_START_DATE)) != 0) {
208 savedSslCertificateStartDate = new Date(domainCursor.getLong(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_START_DATE)));
211 if (domainCursor.getLong(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_END_DATE)) != 0) {
212 savedSslCertificateEndDate = new Date(domainCursor.getLong(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_END_DATE)));
215 // Create `ArrayAdapters` for the `Spinners`and their `entry values`.
216 ArrayAdapter<CharSequence> translatedUserAgentArrayAdapter = ArrayAdapter.createFromResource(context, R.array.translated_domain_settings_user_agent_names, R.layout.domain_settings_spinner_item);
217 ArrayAdapter<CharSequence> fontSizeArrayAdapter = ArrayAdapter.createFromResource(context, R.array.domain_settings_font_size_entries, R.layout.domain_settings_spinner_item);
218 ArrayAdapter<CharSequence> fontSizeEntryValuesArrayAdapter = ArrayAdapter.createFromResource(context, R.array.domain_settings_font_size_entry_values, R.layout.domain_settings_spinner_item);
219 ArrayAdapter<CharSequence> swipeToRefreshArrayAdapter = ArrayAdapter.createFromResource(context, R.array.swipe_to_refresh_array, R.layout.domain_settings_spinner_item);
220 ArrayAdapter<CharSequence> nightModeArrayAdapter = ArrayAdapter.createFromResource(context, R.array.night_mode_array, R.layout.domain_settings_spinner_item);
221 ArrayAdapter<CharSequence> displayImagesArrayAdapter = ArrayAdapter.createFromResource(context, R.array.display_webpage_images_array, R.layout.domain_settings_spinner_item);
223 // Set the `DropDownViewResource` on the `Spinners`.
224 translatedUserAgentArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items);
225 fontSizeArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items);
226 swipeToRefreshArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items);
227 nightModeArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items);
228 displayImagesArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items);
230 // Set the `ArrayAdapters` for the `Spinners`.
231 userAgentSpinner.setAdapter(translatedUserAgentArrayAdapter);
232 fontSizeSpinner.setAdapter(fontSizeArrayAdapter);
233 swipeToRefreshSpinner.setAdapter(swipeToRefreshArrayAdapter);
234 nightModeSpinner.setAdapter(nightModeArrayAdapter);
235 displayWebpageImagesSpinner.setAdapter(displayImagesArrayAdapter);
237 // Create a `SpannableStringBuilder` for each `TextView` that needs multiple colors of text.
238 SpannableStringBuilder savedSslCertificateIssuedToCNameStringBuilder = new SpannableStringBuilder(cNameLabel + savedSslCertificateIssuedToCNameString);
239 SpannableStringBuilder savedSslCertificateIssuedToONameStringBuilder = new SpannableStringBuilder(oNameLabel + savedSslCertificateIssuedToONameString);
240 SpannableStringBuilder savedSslCertificateIssuedToUNameStringBuilder = new SpannableStringBuilder(uNameLabel + savedSslCertificateIssuedToUNameString);
241 SpannableStringBuilder savedSslCertificateIssuedByCNameStringBuilder = new SpannableStringBuilder(cNameLabel + savedSslCertificateIssuedByCNameString);
242 SpannableStringBuilder savedSslCertificateIssuedByONameStringBuilder = new SpannableStringBuilder(oNameLabel + savedSslCertificateIssuedByONameString);
243 SpannableStringBuilder savedSslCertificateIssuedByUNameStringBuilder = new SpannableStringBuilder(uNameLabel + savedSslCertificateIssuedByUNameString);
245 // Initialize the `SpannableStringBuilders` for the SSL certificate dates.
246 SpannableStringBuilder savedSslCertificateStartDateStringBuilder;
247 SpannableStringBuilder savedSslCertificateEndDateStringBuilder;
249 // Leave the SSL certificate dates empty if they are `null`.
250 if (savedSslCertificateStartDate == null) {
251 savedSslCertificateStartDateStringBuilder = new SpannableStringBuilder(startDateLabel);
253 savedSslCertificateStartDateStringBuilder = new SpannableStringBuilder(startDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(savedSslCertificateStartDate));
256 if (savedSslCertificateEndDate == null) {
257 savedSslCertificateEndDateStringBuilder = new SpannableStringBuilder(endDateLabel);
259 savedSslCertificateEndDateStringBuilder = new SpannableStringBuilder(endDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(savedSslCertificateEndDate));
262 // Create a red `ForegroundColorSpan`. We have to use the deprecated `getColor` until API >= 23.
263 final ForegroundColorSpan redColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.red_a700));
265 // Create a blue `ForegroundColorSpan`.
266 final ForegroundColorSpan blueColorSpan;
268 // Set `blueColorSpan` according to the theme. We have to use the deprecated `getColor()` until API >= 23.
269 if (MainWebViewActivity.darkTheme) {
270 //noinspection deprecation
271 blueColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.blue_400));
273 //noinspection deprecation
274 blueColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.blue_700));
277 // Set the domain name from the the database cursor.
278 domainNameEditText.setText(domainNameString);
280 // Update the certificates' `Common Name` color when the domain name text changes.
281 domainNameEditText.addTextChangedListener(new TextWatcher() {
283 public void beforeTextChanged(CharSequence s, int start, int count, int after) {
288 public void onTextChanged(CharSequence s, int start, int before, int count) {
293 public void afterTextChanged(Editable s) {
294 // Get the new domain name.
295 String newDomainName = domainNameEditText.getText().toString();
297 // Check the saved SSL certificate against the new domain name.
298 boolean savedSslCertificateMatchesNewDomainName = checkDomainNameAgainstCertificate(newDomainName, savedSslCertificateIssuedToCNameString);
300 // Create a `SpannableStringBuilder` for the saved certificate `Common Name`.
301 SpannableStringBuilder savedSslCertificateCommonNameStringBuilder = new SpannableStringBuilder(cNameLabel + savedSslCertificateIssuedToCNameString);
303 // Format the saved certificate `Common Name` color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
304 if (savedSslCertificateMatchesNewDomainName) {
305 savedSslCertificateCommonNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), savedSslCertificateCommonNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
307 savedSslCertificateCommonNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), savedSslCertificateCommonNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
310 // Update `savedSslCertificateIssuedToCNameTextView`.
311 savedSslCertificateIssuedToCNameTextView.setText(savedSslCertificateCommonNameStringBuilder);
313 // Update the current website certificate if it exists.
314 if (currentWebsiteSslCertificate != null) {
315 // Get the current website certificate `Common Name`.
316 String currentWebsiteCertificateCommonName = currentWebsiteSslCertificate.getIssuedTo().getCName();
318 // Check the current website certificate against the new domain name.
319 boolean currentWebsiteCertificateMatchesNewDomainName = checkDomainNameAgainstCertificate(newDomainName, currentWebsiteCertificateCommonName);
321 // Create a `SpannableStringBuilder` for the current website certificate `Common Name`.
322 SpannableStringBuilder currentWebsiteCertificateCommonNameStringBuilder = new SpannableStringBuilder(cNameLabel + currentWebsiteCertificateCommonName);
324 // Format the current certificate `Common Name` color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
325 if (currentWebsiteCertificateMatchesNewDomainName) {
326 currentWebsiteCertificateCommonNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), currentWebsiteCertificateCommonNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
328 currentWebsiteCertificateCommonNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), currentWebsiteCertificateCommonNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
331 // Update `currentWebsiteCertificateIssuedToCNameTextView`.
332 currentWebsiteCertificateIssuedToCNameTextView.setText(currentWebsiteCertificateCommonNameStringBuilder);
337 // Create a `boolean` to track if night mode is enabled.
338 boolean nightModeEnabled = (nightModeInt == DomainsDatabaseHelper.NIGHT_MODE_ENABLED) || ((nightModeInt == DomainsDatabaseHelper.NIGHT_MODE_SYSTEM_DEFAULT) && defaultNightModeBoolean);
340 // Disable the JavaScript switch if night mode is enabled.
341 if (nightModeEnabled) {
342 javaScriptEnabledSwitch.setEnabled(false);
344 javaScriptEnabledSwitch.setEnabled(true);
347 // Set the JavaScript icon.
348 if ((javaScriptEnabledInt == 1) || nightModeEnabled) {
349 javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.javascript_enabled));
351 javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.privacy_mode));
354 // Set the JavaScript switch status.
355 if (javaScriptEnabledInt == 1) { // JavaScript is enabled.
356 javaScriptEnabledSwitch.setChecked(true);
357 } else { // JavaScript is disabled.
358 javaScriptEnabledSwitch.setChecked(false);
361 // Set the first-party cookies status. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
362 if (firstPartyCookiesEnabledInt == 1) { // First-party cookies are enabled.
363 firstPartyCookiesEnabledSwitch.setChecked(true);
364 firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_enabled));
365 } else { // First-party cookies are disabled.
366 firstPartyCookiesEnabledSwitch.setChecked(false);
368 // Set the icon according to the theme.
369 if (MainWebViewActivity.darkTheme) {
370 firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_dark));
372 firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_light));
376 // Only display third-party cookies if SDK_INT >= 21.
377 if (Build.VERSION.SDK_INT >= 21) { // Third-party cookies can be configured for API >= 21.
378 // Only enable third-party-cookies if first-party cookies are enabled.
379 if (firstPartyCookiesEnabledInt == 1) { // First-party cookies are enabled.
380 // Set the third-party cookies status. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
381 if (thirdPartyCookiesEnabledInt == 1) { // Both first-party and third-party cookies are enabled.
382 thirdPartyCookiesEnabledSwitch.setChecked(true);
383 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_warning));
384 } else { // First party cookies are enabled but third-party cookies are disabled.
385 thirdPartyCookiesEnabledSwitch.setChecked(false);
387 // Set the icon according to the theme.
388 if (MainWebViewActivity.darkTheme) {
389 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_dark));
391 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_light));
394 } else { // First-party cookies are disabled.
395 // Set the status of third-party cookies.
396 if (thirdPartyCookiesEnabledInt == 1) {
397 thirdPartyCookiesEnabledSwitch.setChecked(true);
399 thirdPartyCookiesEnabledSwitch.setChecked(false);
402 // Disable the third-party cookies switch.
403 thirdPartyCookiesEnabledSwitch.setEnabled(false);
405 // Set the icon according to the theme.
406 if (MainWebViewActivity.darkTheme) {
407 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_ghosted_dark));
409 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_ghosted_light));
412 } else { // Third-party cookies cannot be configured for API <= 21.
413 // Hide the LinearLayout for third-party cookies.
414 thirdPartyCookiesLinearLayout.setVisibility(View.GONE);
417 // Only enable DOM storage if JavaScript is enabled.
418 if ((javaScriptEnabledInt == 1) || nightModeEnabled) { // JavaScript is enabled.
419 // Enable the DOM storage `Switch`.
420 domStorageEnabledSwitch.setEnabled(true);
422 // Set the DOM storage status. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
423 if (domStorageEnabledInt == 1) { // Both JavaScript and DOM storage are enabled.
424 domStorageEnabledSwitch.setChecked(true);
425 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_enabled));
426 } else { // JavaScript is enabled but DOM storage is disabled.
427 // Set the DOM storage switch to off.
428 domStorageEnabledSwitch.setChecked(false);
430 // Set the icon according to the theme.
431 if (MainWebViewActivity.darkTheme) {
432 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_dark));
434 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_light));
437 } else { // JavaScript is disabled.
438 // Disable the DOM storage `Switch`.
439 domStorageEnabledSwitch.setEnabled(false);
441 // Set the checked status of DOM storage.
442 if (domStorageEnabledInt == 1) { // DOM storage is enabled but JavaScript is disabled.
443 domStorageEnabledSwitch.setChecked(true);
444 } else { // Both JavaScript and DOM storage are disabled.
445 domStorageEnabledSwitch.setChecked(false);
448 // Set the icon according to the theme.
449 if (MainWebViewActivity.darkTheme) {
450 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_dark));
452 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_light));
456 // Set the form data status. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons. Form data can be removed once the minimum API >= 26.
457 if (Build.VERSION.SDK_INT >= 26) { // Form data no longer applies to newer versions of Android.
458 // Hide the form data switch.
459 formDataEnabledSwitch.setVisibility(View.GONE);
460 } else { // Form data should be displayed because this is an older version of Android.
461 if (formDataEnabledInt == 1) { // Form data is on.
462 formDataEnabledSwitch.setChecked(true);
463 formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_enabled));
464 } else { // Form data is off.
465 // Turn the form data switch to off.
466 formDataEnabledSwitch.setChecked(false);
468 // Set the icon according to the theme.
469 if (MainWebViewActivity.darkTheme) {
470 formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_disabled_dark));
472 formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_disabled_light));
477 // Set the EasyList status. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
478 if (easyListEnabledInt == 1) { // EasyList is on.
479 // Turn the switch on.
480 easyListSwitch.setChecked(true);
482 // Set the icon according to the theme.
483 if (MainWebViewActivity.darkTheme) {
484 easyListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_enabled_dark));
486 easyListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_enabled_light));
488 } else { // EasyList is off.
489 // Turn the switch off.
490 easyListSwitch.setChecked(false);
492 // Set the icon according to the theme.
493 if (MainWebViewActivity.darkTheme) {
494 easyListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_disabled_dark));
496 easyListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_disabled_light));
500 // Set the EasyPrivacy status. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
501 if (easyPrivacyEnabledInt == 1) { // EasyPrivacy is on.
502 // Turn the switch on.
503 easyPrivacySwitch.setChecked(true);
505 // Set the icon according to the theme.
506 if (MainWebViewActivity.darkTheme) {
507 easyPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_enabled_dark));
509 easyPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_enabled_light));
511 } else { // EasyPrivacy is off.
512 // Turn the switch off.
513 easyPrivacySwitch.setChecked(false);
515 // Set the icon according to the theme.
516 if (MainWebViewActivity.darkTheme) {
517 easyPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_disabled_dark));
519 easyPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_disabled_light));
523 // Set the Fanboy's Annoyance List status. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
524 if (fanboysAnnoyanceListInt == 1) { // Fanboy's Annoyance List is on.
525 // Turn the switch on.
526 fanboysAnnoyanceListSwitch.setChecked(true);
528 // Set the icon according to the theme.
529 if (MainWebViewActivity.darkTheme) {
530 fanboysAnnoyanceListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_dark));
532 fanboysAnnoyanceListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_light));
534 } else { // Fanboy's Annoyance List is off.
535 // Turn the switch off.
536 fanboysAnnoyanceListSwitch.setChecked(false);
538 // Set the icon according to the theme.
539 if (MainWebViewActivity.darkTheme) {
540 fanboysAnnoyanceListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_dark));
542 fanboysAnnoyanceListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_light));
546 // Only enable Fanboy's Social Blocking List if Fanboy's Annoyance List is off.
547 if (fanboysAnnoyanceListInt == 0) { // Fanboy's Annoyance List is on.
548 // Enable Fanboy's Social Blocking List. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
549 if (fanboysSocialBlockingListInt == 1) { // Fanboy's Social Blocking List is on.
550 // Enable the switch and turn it on.
551 fanboysSocialBlockingListSwitch.setEnabled(true);
552 fanboysSocialBlockingListSwitch.setChecked(true);
554 // Set the icon according to the theme.
555 if (MainWebViewActivity.darkTheme) {
556 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_dark));
558 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_light));
560 } else { // Fanboy's Social Blocking List is off.
561 // Enable the switch but turn it off.
562 fanboysSocialBlockingListSwitch.setEnabled(true);
563 fanboysSocialBlockingListSwitch.setChecked(false);
565 // Set the icon according to the theme.
566 if (MainWebViewActivity.darkTheme) {
567 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_dark));
569 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_light));
572 } else { // Fanboy's Annoyance List is on.
573 // Disable Fanboy's Social Blocking List. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
574 if (fanboysSocialBlockingListInt == 1) { // Fanboy's Social Blocking List is on.
575 // Disable the switch but turn it on.
576 fanboysSocialBlockingListSwitch.setEnabled(false);
577 fanboysSocialBlockingListSwitch.setChecked(true);
578 } else { // Fanboy's Social Blocking List is off.
579 // Disable the switch and turn it off.
580 fanboysSocialBlockingListSwitch.setEnabled(false);
581 fanboysSocialBlockingListSwitch.setChecked(false);
584 // Set the icon according to the theme.
585 if (MainWebViewActivity.darkTheme) {
586 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_ghosted_dark));
588 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_ghosted_light));
592 // Inflated a WebView to get the default user agent.
593 // `@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.
594 @SuppressLint("InflateParams") View bareWebViewLayout = inflater.inflate(R.layout.bare_webview, null, false);
595 WebView bareWebView = bareWebViewLayout.findViewById(R.id.bare_webview);
596 final String webViewDefaultUserAgentString = bareWebView.getSettings().getUserAgentString();
598 // Get a handle for the user agent array adapter. This array does not contain the `System default` entry.
599 ArrayAdapter<CharSequence> userAgentNamesArray = ArrayAdapter.createFromResource(context, R.array.user_agent_names, R.layout.domain_settings_spinner_item);
601 // Get the positions of the user agent and the default user agent.
602 int userAgentArrayPosition = userAgentNamesArray.getPosition(currentUserAgentName);
603 int defaultUserAgentArrayPosition = userAgentNamesArray.getPosition(defaultUserAgentName);
605 // Get a handle for the user agent data array. This array does not contain the `System default` entry.
606 String[] userAgentDataArray = resources.getStringArray(R.array.user_agent_data);
608 // Set the user agent text.
609 if (currentUserAgentName.equals(getString(R.string.system_default_user_agent))) { // Use the system default user agent.
610 // Set the user agent according to the system default.
611 switch (defaultUserAgentArrayPosition) {
612 case MainWebViewActivity.UNRECOGNIZED_USER_AGENT: // The default user agent name is not on the canonical list.
613 // This is probably because it was set in an older version of Privacy Browser before the switch to persistent user agent names.
614 userAgentTextView.setText(defaultUserAgentName);
617 case MainWebViewActivity.SETTINGS_WEBVIEW_DEFAULT_USER_AGENT:
618 // Display the `WebView` default user agent.
619 userAgentTextView.setText(webViewDefaultUserAgentString);
622 case MainWebViewActivity.SETTINGS_CUSTOM_USER_AGENT:
623 // Display the custom user agent.
624 userAgentTextView.setText(defaultCustomUserAgentString);
628 // Get the user agent string from the user agent data array.
629 userAgentTextView.setText(userAgentDataArray[defaultUserAgentArrayPosition]);
631 } else if (userAgentArrayPosition == MainWebViewActivity.UNRECOGNIZED_USER_AGENT) { // A custom user agent is stored in the current user agent name.
632 // Set the user agent spinner to `Custom user agent`.
633 userAgentSpinner.setSelection(MainWebViewActivity.DOMAINS_CUSTOM_USER_AGENT);
635 // Hide the user agent TextView.
636 userAgentTextView.setVisibility(View.GONE);
638 // Show the custom user agent EditText and set the current user agent name as the text.
639 customUserAgentEditText.setVisibility(View.VISIBLE);
640 customUserAgentEditText.setText(currentUserAgentName);
641 } else { // The user agent name contains one of the canonical user agents.
642 // 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.
643 userAgentSpinner.setSelection(userAgentArrayPosition + 1);
645 // Show the user agent TextView.
646 userAgentTextView.setVisibility(View.VISIBLE);
648 // Hide the custom user agent EditText.
649 customUserAgentEditText.setVisibility(View.GONE);
651 // Set the user agent text.
652 switch (userAgentArrayPosition) {
653 case MainWebViewActivity.DOMAINS_WEBVIEW_DEFAULT_USER_AGENT:
654 // Display the WebView default user agent.
655 userAgentTextView.setText(webViewDefaultUserAgentString);
659 // 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.
660 userAgentTextView.setText(userAgentDataArray[userAgentArrayPosition + 1]);
664 // Open the user agent spinner when the TextView is clicked.
665 userAgentTextView.setOnClickListener((View v) -> {
666 // Open the user agent spinner.
667 userAgentSpinner.performClick();
670 // Set the selected font size.
671 int fontSizeArrayPosition = fontSizeEntryValuesArrayAdapter.getPosition(String.valueOf(fontSizeInt));
672 fontSizeSpinner.setSelection(fontSizeArrayPosition);
674 // Set the default font size text.
675 int defaultFontSizeArrayPosition = fontSizeEntryValuesArrayAdapter.getPosition(defaultFontSizeString);
676 fontSizeTextView.setText(fontSizeArrayAdapter.getItem(defaultFontSizeArrayPosition));
678 // Set the display options for the font size TextView.
679 if (fontSizeArrayPosition == 0) { // System default font size is selected. Display `fontSizeTextView`.
680 fontSizeTextView.setVisibility(View.VISIBLE);
681 } else { // A custom font size is specified. Hide `fontSizeTextView`.
682 fontSizeTextView.setVisibility(View.GONE);
685 // Open the font size spinner when the TextView is clicked.
686 fontSizeTextView.setOnClickListener((View v) -> {
687 // Open the user agent spinner.
688 fontSizeSpinner.performClick();
691 // Display the swipe to refresh selection in the spinner.
692 swipeToRefreshSpinner.setSelection(swipeToRefreshInt);
694 // Set the swipe to refresh text.
695 if (defaultSwipeToRefreshBoolean) {
696 swipeToRefreshTextView.setText(swipeToRefreshArrayAdapter.getItem(DomainsDatabaseHelper.SWIPE_TO_REFRESH_ENABLED));
698 swipeToRefreshTextView.setText(swipeToRefreshArrayAdapter.getItem(DomainsDatabaseHelper.SWIPE_TO_REFRESH_DISABLED));
701 // Set the swipe to refresh icon and TextView settings. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
702 switch (swipeToRefreshInt) {
703 case DomainsDatabaseHelper.SWIPE_TO_REFRESH_SYSTEM_DEFAULT:
704 if (defaultSwipeToRefreshBoolean) { // Swipe to refresh is enabled by default.
705 // Set the icon according to the theme.
706 if (MainWebViewActivity.darkTheme) {
707 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_enabled_dark));
709 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_enabled_light));
711 } else { // Swipe to refresh is disabled by default
712 // Set the icon according to the theme.
713 if (MainWebViewActivity.darkTheme) {
714 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_disabled_dark));
716 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_disabled_light));
720 // Show the swipe to refresh TextView.
721 swipeToRefreshTextView.setVisibility(View.VISIBLE);
724 case DomainsDatabaseHelper.SWIPE_TO_REFRESH_ENABLED:
725 // Set the icon according to the theme.
726 if (MainWebViewActivity.darkTheme) {
727 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_enabled_dark));
729 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_enabled_light));
732 // Hide the swipe to refresh TextView.`
733 swipeToRefreshTextView.setVisibility(View.GONE);
736 case DomainsDatabaseHelper.SWIPE_TO_REFRESH_DISABLED:
737 // Set the icon according to the theme.
738 if (MainWebViewActivity.darkTheme) {
739 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_disabled_dark));
741 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_disabled_light));
744 // Hide the swipe to refresh TextView.
745 swipeToRefreshTextView.setVisibility(View.GONE);
748 // Open the swipe to refresh spinner when the TextView is clicked.
749 swipeToRefreshTextView.setOnClickListener((View v) -> {
750 // Open the swipe to refresh spinner.
751 swipeToRefreshSpinner.performClick();
754 // Display the night mode in the spinner.
755 nightModeSpinner.setSelection(nightModeInt);
757 // Set the default night mode text.
758 if (defaultNightModeBoolean) {
759 nightModeTextView.setText(nightModeArrayAdapter.getItem(DomainsDatabaseHelper.NIGHT_MODE_ENABLED));
761 nightModeTextView.setText(nightModeArrayAdapter.getItem(DomainsDatabaseHelper.NIGHT_MODE_DISABLED));
764 // Set the night mode icon and TextView settings. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
765 switch (nightModeInt) {
766 case DomainsDatabaseHelper.NIGHT_MODE_SYSTEM_DEFAULT:
767 if (defaultNightModeBoolean) { // Night mode enabled by default.
768 // Set the icon according to the theme.
769 if (MainWebViewActivity.darkTheme) {
770 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_dark));
772 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_light));
774 } else { // Night mode disabled by default.
775 // Set the icon according to the theme.
776 if (MainWebViewActivity.darkTheme) {
777 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_dark));
779 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_light));
783 // Show night mode TextView.
784 nightModeTextView.setVisibility(View.VISIBLE);
787 case DomainsDatabaseHelper.NIGHT_MODE_ENABLED:
788 // Set the icon according to the theme.
789 if (MainWebViewActivity.darkTheme) {
790 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_dark));
792 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_light));
795 // Hide the night mode TextView.
796 nightModeTextView.setVisibility(View.GONE);
799 case DomainsDatabaseHelper.NIGHT_MODE_DISABLED:
800 // Set the icon according to the theme.
801 if (MainWebViewActivity.darkTheme) {
802 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_dark));
804 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_light));
807 // Hide the night mode TextView.
808 nightModeTextView.setVisibility(View.GONE);
812 // Open the night mode spinner when the TextView is clicked.
813 nightModeTextView.setOnClickListener((View v) -> {
814 // Open the night mode spinner.
815 nightModeSpinner.performClick();
818 // Display the website images mode in the spinner.
819 displayWebpageImagesSpinner.setSelection(displayImagesInt);
821 // Set the default display images text.
822 if (defaultDisplayWebpageImagesBoolean) {
823 displayImagesTextView.setText(displayImagesArrayAdapter.getItem(DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_ENABLED));
825 displayImagesTextView.setText(displayImagesArrayAdapter.getItem(DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_DISABLED));
828 // Set the display website images icon and TextView settings. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
829 switch (displayImagesInt) {
830 case DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_SYSTEM_DEFAULT:
831 if (defaultDisplayWebpageImagesBoolean) { // Display webpage images enabled by default.
832 // Set the icon according to the theme.
833 if (MainWebViewActivity.darkTheme) {
834 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_dark));
836 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_light));
838 } else { // Display webpage images disabled by default.
839 // Set the icon according to the theme.
840 if (MainWebViewActivity.darkTheme) {
841 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_dark));
843 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_light));
847 // Show the display images TextView.
848 displayImagesTextView.setVisibility(View.VISIBLE);
851 case DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_ENABLED:
852 // Set the icon according to the theme.
853 if (MainWebViewActivity.darkTheme) {
854 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_dark));
856 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_light));
859 // Hide the display images TextView.
860 displayImagesTextView.setVisibility(View.GONE);
863 case DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_DISABLED:
864 // Set the icon according to the theme.
865 if (MainWebViewActivity.darkTheme) {
866 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_dark));
868 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_light));
871 // Hide the display images TextView.
872 displayImagesTextView.setVisibility(View.GONE);
876 // Open the display images spinner when the TextView is clicked.
877 displayImagesTextView.setOnClickListener((View v) -> {
878 // Open the user agent spinner.
879 displayWebpageImagesSpinner.performClick();
882 // Set the pinned SSL certificate icon.
883 if (pinnedSslCertificateInt == 1) { // Pinned SSL certificate is enabled. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
885 pinnedSslCertificateSwitch.setChecked(true);
887 // Set the icon according to the theme.
888 if (MainWebViewActivity.darkTheme) {
889 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_dark));
891 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_light));
893 } else { // Pinned SSL certificate is disabled.
894 // Uncheck the switch.
895 pinnedSslCertificateSwitch.setChecked(false);
897 // Set the icon according to the theme.
898 if (MainWebViewActivity.darkTheme) {
899 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_dark));
901 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_light));
905 // Store the current date.
906 Date currentDate = Calendar.getInstance().getTime();
908 // Setup the `StringBuilders` to display the general certificate information in blue. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
909 savedSslCertificateIssuedToONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), savedSslCertificateIssuedToONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
910 savedSslCertificateIssuedToUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), savedSslCertificateIssuedToUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
911 savedSslCertificateIssuedByCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), savedSslCertificateIssuedByCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
912 savedSslCertificateIssuedByONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), savedSslCertificateIssuedByONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
913 savedSslCertificateIssuedByUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), savedSslCertificateIssuedByUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
915 // Check the certificate `Common Name` against the domain name.
916 boolean savedSSlCertificateCommonNameMatchesDomainName = checkDomainNameAgainstCertificate(domainNameString, savedSslCertificateIssuedToCNameString);
918 // Format the `issuedToCommonName` color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
919 if (savedSSlCertificateCommonNameMatchesDomainName) {
920 savedSslCertificateIssuedToCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), savedSslCertificateIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
922 savedSslCertificateIssuedToCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), savedSslCertificateIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
925 // Format the start date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
926 if ((savedSslCertificateStartDate != null) && savedSslCertificateStartDate.after(currentDate)) { // The certificate start date is in the future.
927 savedSslCertificateStartDateStringBuilder.setSpan(redColorSpan, startDateLabel.length(), savedSslCertificateStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
928 } else { // The certificate start date is in the past.
929 savedSslCertificateStartDateStringBuilder.setSpan(blueColorSpan, startDateLabel.length(), savedSslCertificateStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
932 // Format the end date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
933 if ((savedSslCertificateEndDate != null) && savedSslCertificateEndDate.before(currentDate)) { // The certificate end date is in the past.
934 savedSslCertificateEndDateStringBuilder.setSpan(redColorSpan, endDateLabel.length(), savedSslCertificateEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
935 } else { // The certificate end date is in the future.
936 savedSslCertificateEndDateStringBuilder.setSpan(blueColorSpan, endDateLabel.length(), savedSslCertificateEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
939 // Display the current website SSL certificate strings.
940 savedSslCertificateIssuedToCNameTextView.setText(savedSslCertificateIssuedToCNameStringBuilder);
941 savedSslCertificateIssuedToONameTextView.setText(savedSslCertificateIssuedToONameStringBuilder);
942 savedSslCertificateIssuedToUNameTextView.setText(savedSslCertificateIssuedToUNameStringBuilder);
943 savedSslCertificateIssuedByCNameTextView.setText(savedSslCertificateIssuedByCNameStringBuilder);
944 savedSslCertificateIssuedByONameTextView.setText(savedSslCertificateIssuedByONameStringBuilder);
945 savedSslCertificateIssuedByUNameTextView.setText(savedSslCertificateIssuedByUNameStringBuilder);
946 savedSslCertificateStartDateTextView.setText(savedSslCertificateStartDateStringBuilder);
947 savedSslCertificateEndDateTextView.setText(savedSslCertificateEndDateStringBuilder);
949 // Populate the current website SSL certificate if there is one.
950 if (currentWebsiteSslCertificate != null) {
951 // Get the strings from the SSL certificate.
952 String currentWebsiteCertificateIssuedToCNameString = currentWebsiteSslCertificate.getIssuedTo().getCName();
953 String currentWebsiteCertificateIssuedToONameString = currentWebsiteSslCertificate.getIssuedTo().getOName();
954 String currentWebsiteCertificateIssuedToUNameString = currentWebsiteSslCertificate.getIssuedTo().getUName();
955 String currentWebsiteCertificateIssuedByCNameString = currentWebsiteSslCertificate.getIssuedBy().getCName();
956 String currentWebsiteCertificateIssuedByONameString = currentWebsiteSslCertificate.getIssuedBy().getOName();
957 String currentWebsiteCertificateIssuedByUNameString = currentWebsiteSslCertificate.getIssuedBy().getUName();
958 Date currentWebsiteCertificateStartDate = currentWebsiteSslCertificate.getValidNotBeforeDate();
959 Date currentWebsiteCertificateEndDate = currentWebsiteSslCertificate.getValidNotAfterDate();
961 // Create a `SpannableStringBuilder` for each `TextView` that needs multiple colors of text.
962 SpannableStringBuilder currentWebsiteCertificateIssuedToCNameStringBuilder = new SpannableStringBuilder(cNameLabel + currentWebsiteCertificateIssuedToCNameString);
963 SpannableStringBuilder currentWebsiteCertificateIssuedToONameStringBuilder = new SpannableStringBuilder(oNameLabel + currentWebsiteCertificateIssuedToONameString);
964 SpannableStringBuilder currentWebsiteCertificateIssuedToUNameStringBuilder = new SpannableStringBuilder(uNameLabel + currentWebsiteCertificateIssuedToUNameString);
965 SpannableStringBuilder currentWebsiteCertificateIssuedByCNameStringBuilder = new SpannableStringBuilder(cNameLabel + currentWebsiteCertificateIssuedByCNameString);
966 SpannableStringBuilder currentWebsiteCertificateIssuedByONameStringBuilder = new SpannableStringBuilder(oNameLabel + currentWebsiteCertificateIssuedByONameString);
967 SpannableStringBuilder currentWebsiteCertificateIssuedByUNameStringBuilder = new SpannableStringBuilder(uNameLabel + currentWebsiteCertificateIssuedByUNameString);
968 SpannableStringBuilder currentWebsiteCertificateStartDateStringBuilder = new SpannableStringBuilder(startDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG)
969 .format(currentWebsiteCertificateStartDate));
970 SpannableStringBuilder currentWebsiteCertificateEndDateStringBuilder = new SpannableStringBuilder(endDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG)
971 .format(currentWebsiteCertificateEndDate));
973 // Setup the `StringBuilders` to display the general certificate information in blue. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
974 currentWebsiteCertificateIssuedToONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), currentWebsiteCertificateIssuedToONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
975 currentWebsiteCertificateIssuedToUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), currentWebsiteCertificateIssuedToUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
976 currentWebsiteCertificateIssuedByCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), currentWebsiteCertificateIssuedByCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
977 currentWebsiteCertificateIssuedByONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), currentWebsiteCertificateIssuedByONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
978 currentWebsiteCertificateIssuedByUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), currentWebsiteCertificateIssuedByUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
980 // Check the certificate `Common Name` against the domain name.
981 boolean currentWebsiteCertificateCommonNameMatchesDomainName = checkDomainNameAgainstCertificate(domainNameString, currentWebsiteCertificateIssuedToCNameString);
983 // Format the `issuedToCommonName` color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
984 if (currentWebsiteCertificateCommonNameMatchesDomainName) {
985 currentWebsiteCertificateIssuedToCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), currentWebsiteCertificateIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
987 currentWebsiteCertificateIssuedToCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), currentWebsiteCertificateIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
990 // Format the start date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
991 if (currentWebsiteCertificateStartDate.after(currentDate)) { // The certificate start date is in the future.
992 currentWebsiteCertificateStartDateStringBuilder.setSpan(redColorSpan, startDateLabel.length(), currentWebsiteCertificateStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
993 } else { // The certificate start date is in the past.
994 currentWebsiteCertificateStartDateStringBuilder.setSpan(blueColorSpan, startDateLabel.length(), currentWebsiteCertificateStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
997 // Format the end date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
998 if (currentWebsiteCertificateEndDate.before(currentDate)) { // The certificate end date is in the past.
999 currentWebsiteCertificateEndDateStringBuilder.setSpan(redColorSpan, endDateLabel.length(), currentWebsiteCertificateEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1000 } else { // The certificate end date is in the future.
1001 currentWebsiteCertificateEndDateStringBuilder.setSpan(blueColorSpan, endDateLabel.length(), currentWebsiteCertificateEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1004 // Display the current website SSL certificate strings.
1005 currentWebsiteCertificateIssuedToCNameTextView.setText(currentWebsiteCertificateIssuedToCNameStringBuilder);
1006 currentWebsiteCertificateIssuedToONameTextView.setText(currentWebsiteCertificateIssuedToONameStringBuilder);
1007 currentWebsiteCertificateIssuedToUNameTextView.setText(currentWebsiteCertificateIssuedToUNameStringBuilder);
1008 currentWebsiteCertificateIssuedByCNameTextView.setText(currentWebsiteCertificateIssuedByCNameStringBuilder);
1009 currentWebsiteCertificateIssuedByONameTextView.setText(currentWebsiteCertificateIssuedByONameStringBuilder);
1010 currentWebsiteCertificateIssuedByUNameTextView.setText(currentWebsiteCertificateIssuedByUNameStringBuilder);
1011 currentWebsiteCertificateStartDateTextView.setText(currentWebsiteCertificateStartDateStringBuilder);
1012 currentWebsiteCertificateEndDateTextView.setText(currentWebsiteCertificateEndDateStringBuilder);
1015 // Set the initial display status for the SSL certificates.
1016 if (pinnedSslCertificateSwitch.isChecked()) {
1017 // Set the visibility of the saved SSL certificate.
1018 if (savedSslCertificateIssuedToCNameString == null) {
1019 savedSslCertificateLinearLayout.setVisibility(View.GONE);
1021 savedSslCertificateLinearLayout.setVisibility(View.VISIBLE);
1024 // Set the visibility of the current website SSL certificate.
1025 if (currentWebsiteSslCertificate == null) {
1026 // Hide the SSL certificate.
1027 currentWebsiteCertificateLinearLayout.setVisibility(View.GONE);
1029 // Show the instruction.
1030 noCurrentWebsiteCertificateTextView.setVisibility(View.VISIBLE);
1032 // Show the SSL certificate.
1033 currentWebsiteCertificateLinearLayout.setVisibility(View.VISIBLE);
1035 // Hide the instruction.
1036 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
1039 // Set the status of the radio buttons.
1040 if (savedSslCertificateLinearLayout.getVisibility() == View.VISIBLE) { // The saved SSL certificate is displayed.
1041 savedSslCertificateRadioButton.setChecked(true);
1042 currentWebsiteCertificateRadioButton.setChecked(false);
1043 } else if (currentWebsiteCertificateLinearLayout.getVisibility() == View.VISIBLE) { // The saved SSL certificate is hidden but the current website SSL certificate is visible.
1044 currentWebsiteCertificateRadioButton.setChecked(true);
1045 savedSslCertificateRadioButton.setChecked(false);
1046 } else { // Neither SSL certificate is visible.
1047 savedSslCertificateRadioButton.setChecked(false);
1048 currentWebsiteCertificateRadioButton.setChecked(false);
1050 } else { // `pinnedSslCertificateSwitch` is not checked.
1051 // Hide the SSl certificates and instructions.
1052 savedSslCertificateLinearLayout.setVisibility(View.GONE);
1053 currentWebsiteCertificateLinearLayout.setVisibility(View.GONE);
1054 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
1056 // Uncheck the radio buttons.
1057 savedSslCertificateRadioButton.setChecked(false);
1058 currentWebsiteCertificateRadioButton.setChecked(false);
1062 // Set the JavaScript switch listener.
1063 javaScriptEnabledSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1064 if (isChecked) { // JavaScript is enabled.
1065 // Update the JavaScript icon.
1066 javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.javascript_enabled));
1068 // Enable the DOM storage `Switch`.
1069 domStorageEnabledSwitch.setEnabled(true);
1071 // Update the DOM storage icon.
1072 if (domStorageEnabledSwitch.isChecked()) { // DOM storage is enabled.
1073 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_enabled));
1074 } else { // DOM storage is disabled.
1075 // Set the icon according to the theme.
1076 if (MainWebViewActivity.darkTheme) {
1077 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_dark));
1079 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_light));
1082 } else { // JavaScript is disabled.
1083 // Update the JavaScript icon.
1084 javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.privacy_mode));
1086 // Disable the DOM storage `Switch`.
1087 domStorageEnabledSwitch.setEnabled(false);
1089 // Set the DOM storage icon according to the theme.
1090 if (MainWebViewActivity.darkTheme) {
1091 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_dark));
1093 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_light));
1098 // Set the first-party cookies switch listener.
1099 firstPartyCookiesEnabledSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1100 if (isChecked) { // First-party cookies are enabled.
1101 // Update the first-party cookies icon.
1102 firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_enabled));
1104 // Enable the third-party cookies switch.
1105 thirdPartyCookiesEnabledSwitch.setEnabled(true);
1107 // Update the third-party cookies icon.
1108 if (thirdPartyCookiesEnabledSwitch.isChecked()) { // Third-party cookies are enabled.
1109 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_warning));
1110 } else { // Third-party cookies are disabled.
1111 // Set the third-party cookies icon according to the theme.
1112 if (MainWebViewActivity.darkTheme) {
1113 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_dark));
1115 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_light));
1118 } else { // First-party cookies are disabled.
1119 // Update the first-party cookies icon according to the theme.
1120 if (MainWebViewActivity.darkTheme) {
1121 firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_dark));
1123 firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_light));
1126 // Disable the third-party cookies switch.
1127 thirdPartyCookiesEnabledSwitch.setEnabled(false);
1129 // Set the third-party cookies icon according to the theme.
1130 if (MainWebViewActivity.darkTheme) {
1131 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_ghosted_dark));
1133 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_ghosted_light));
1138 // Set the third-party cookies switch listener.
1139 thirdPartyCookiesEnabledSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1142 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_warning));
1144 // Update the third-party cookies icon according to the theme.
1145 if (MainWebViewActivity.darkTheme) {
1146 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_dark));
1148 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_light));
1153 // Set the DOM Storage switch listener.
1154 domStorageEnabledSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1157 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_enabled));
1159 // Set the icon according to the theme.
1160 if (MainWebViewActivity.darkTheme) {
1161 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_dark));
1163 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_light));
1168 // Set the form data switch listener. It can be removed once the minimum API >= 26.
1169 if (Build.VERSION.SDK_INT < 26) {
1170 formDataEnabledSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1173 formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_enabled));
1175 // Set the icon according to the theme.
1176 if (MainWebViewActivity.darkTheme) {
1177 formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_disabled_dark));
1179 formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_disabled_light));
1185 // Set the EasyList switch listener.
1186 easyListSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1188 if (isChecked) { // EasyList is on.
1189 // Set the icon according to the theme.
1190 if (MainWebViewActivity.darkTheme) {
1191 easyListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_enabled_dark));
1193 easyListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_enabled_light));
1195 } else { // EasyList is off.
1196 // Set the icon according to the theme.
1197 if (MainWebViewActivity.darkTheme) {
1198 easyListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_disabled_dark));
1200 easyListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_disabled_light));
1205 // Set the EasyPrivacy switch listener.
1206 easyPrivacySwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1208 if (isChecked) { // EasyPrivacy is on.
1209 // Set the icon according to the theme.
1210 if (MainWebViewActivity.darkTheme) {
1211 easyPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_enabled_dark));
1213 easyPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_enabled_light));
1215 } else { // EasyPrivacy is off.
1216 // Set the icon according to the theme.
1217 if (MainWebViewActivity.darkTheme) {
1218 easyPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_disabled_dark));
1220 easyPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_disabled_light));
1225 // Set the Fanboy's Annoyance List switch listener.
1226 fanboysAnnoyanceListSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1227 // Update the icon and Fanboy's Social Blocking List.
1228 if (isChecked) { // Fanboy's Annoyance List is on.
1229 // Set the icon according to the theme.
1230 if (MainWebViewActivity.darkTheme) {
1231 fanboysAnnoyanceListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_dark));
1233 fanboysAnnoyanceListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_light));
1236 // Disable the Fanboy's Social Blocking List switch.
1237 fanboysSocialBlockingListSwitch.setEnabled(false);
1239 // Update the Fanboy's Social Blocking List icon according to the theme.
1240 if (MainWebViewActivity.darkTheme) {
1241 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_ghosted_dark));
1243 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_ghosted_light));
1245 } else { // Fanboy's Annoyance List is off.
1246 // Set the icon according to the theme.
1247 if (MainWebViewActivity.darkTheme) {
1248 fanboysAnnoyanceListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_dark));
1250 fanboysAnnoyanceListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_light));
1253 // Enable the Fanboy's Social Blocking List switch.
1254 fanboysSocialBlockingListSwitch.setEnabled(true);
1256 // Update the Fanboy's Social Blocking List icon.
1257 if (fanboysSocialBlockingListSwitch.isChecked()) { // Fanboy's Social Blocking List is on.
1258 // Update the icon according to the theme.
1259 if (MainWebViewActivity.darkTheme) {
1260 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_dark));
1262 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_light));
1264 } else { // Fanboy's Social Blocking List is off.
1265 // Update the icon according to the theme.
1266 if (MainWebViewActivity.darkTheme) {
1267 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_dark));
1269 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_light));
1276 // Set the Fanboy's Social Blocking List switch listener.
1277 fanboysSocialBlockingListSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1279 if (isChecked) { // Fanboy's Social Blocking List is on.
1280 // Set the icon according to the theme.
1281 if (MainWebViewActivity.darkTheme) {
1282 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_dark));
1284 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_light));
1286 } else { // Fanboy's Social Blocking List is off.
1287 // Set the icon according to the theme.
1288 if (MainWebViewActivity.darkTheme) {
1289 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_dark));
1291 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_light));
1296 // Set the user agent spinner listener.
1297 userAgentSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1299 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1300 // Set the new user agent.
1302 case MainWebViewActivity.DOMAINS_SYSTEM_DEFAULT_USER_AGENT:
1303 // Show the user agent TextView.
1304 userAgentTextView.setVisibility(View.VISIBLE);
1306 // Hide the custom user agent EditText.
1307 customUserAgentEditText.setVisibility(View.GONE);
1309 // Set the user text.
1310 switch (defaultUserAgentArrayPosition) {
1311 case MainWebViewActivity.UNRECOGNIZED_USER_AGENT: // The default user agent name is not on the canonical list.
1312 // This is probably because it was set in an older version of Privacy Browser before the switch to persistent user agent names.
1313 userAgentTextView.setText(defaultUserAgentName);
1316 case MainWebViewActivity.SETTINGS_WEBVIEW_DEFAULT_USER_AGENT:
1317 // Display the `WebView` default user agent.
1318 userAgentTextView.setText(webViewDefaultUserAgentString);
1321 case MainWebViewActivity.SETTINGS_CUSTOM_USER_AGENT:
1322 // Display the custom user agent.
1323 userAgentTextView.setText(defaultCustomUserAgentString);
1327 // Get the user agent string from the user agent data array.
1328 userAgentTextView.setText(userAgentDataArray[defaultUserAgentArrayPosition]);
1332 case MainWebViewActivity.DOMAINS_WEBVIEW_DEFAULT_USER_AGENT:
1333 // Show the user agent TextView and set the text.
1334 userAgentTextView.setVisibility(View.VISIBLE);
1335 userAgentTextView.setText(webViewDefaultUserAgentString);
1337 // Hide the custom user agent EditTex.
1338 customUserAgentEditText.setVisibility(View.GONE);
1341 case MainWebViewActivity.DOMAINS_CUSTOM_USER_AGENT:
1342 // Hide the user agent TextView.
1343 userAgentTextView.setVisibility(View.GONE);
1345 // Show the custom user agent EditText and set the current user agent name as the text.
1346 customUserAgentEditText.setVisibility(View.VISIBLE);
1347 customUserAgentEditText.setText(currentUserAgentName);
1351 // 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.
1352 userAgentTextView.setVisibility(View.VISIBLE);
1353 userAgentTextView.setText(userAgentDataArray[position - 1]);
1355 // Hide `customUserAgentEditText`.
1356 customUserAgentEditText.setVisibility(View.GONE);
1361 public void onNothingSelected(AdapterView<?> parent) {
1366 // Set the font size spinner listener.
1367 fontSizeSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1369 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1370 // Update the display options for `fontSizeTextView`.
1371 if (position == 0) { // System default font size has been selected. Display `fontSizeTextView`.
1372 fontSizeTextView.setVisibility(View.VISIBLE);
1373 } else { // A custom font size has been selected. Hide `fontSizeTextView`.
1374 fontSizeTextView.setVisibility(View.GONE);
1379 public void onNothingSelected(AdapterView<?> parent) {
1384 // Set the swipe to refresh spinner listener.
1385 swipeToRefreshSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1387 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1388 // Update the icon and the visibility of `nightModeTextView`. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
1390 case DomainsDatabaseHelper.SWIPE_TO_REFRESH_SYSTEM_DEFAULT:
1391 if (defaultSwipeToRefreshBoolean) { // Swipe to refresh enabled by default.
1392 // Set the icon according to the theme.
1393 if (MainWebViewActivity.darkTheme) {
1394 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_enabled_dark));
1396 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_enabled_light));
1398 } else { // Swipe to refresh disabled by default.
1399 // Set the icon according to the theme.
1400 if (MainWebViewActivity.darkTheme) {
1401 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_disabled_dark));
1403 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_disabled_light));
1407 // Show the swipe to refresh TextView.
1408 swipeToRefreshTextView.setVisibility(View.VISIBLE);
1411 case DomainsDatabaseHelper.SWIPE_TO_REFRESH_ENABLED:
1412 // Set the icon according to the theme.
1413 if (MainWebViewActivity.darkTheme) {
1414 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_enabled_dark));
1416 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_enabled_light));
1419 // Hide the swipe to refresh TextView.
1420 swipeToRefreshTextView.setVisibility(View.GONE);
1423 case DomainsDatabaseHelper.SWIPE_TO_REFRESH_DISABLED:
1424 // Set the icon according to the theme.
1425 if (MainWebViewActivity.darkTheme) {
1426 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_disabled_dark));
1428 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_disabled_light));
1431 // Hide the swipe to refresh TextView.
1432 swipeToRefreshTextView.setVisibility(View.GONE);
1437 public void onNothingSelected(AdapterView<?> parent) {
1442 // Set the night mode spinner listener.
1443 nightModeSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1445 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1446 // Update the icon and the visibility of `nightModeTextView`. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
1448 case DomainsDatabaseHelper.NIGHT_MODE_SYSTEM_DEFAULT:
1449 if (defaultNightModeBoolean) { // Night mode enabled by default.
1450 // Set the icon according to the theme.
1451 if (MainWebViewActivity.darkTheme) {
1452 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_dark));
1454 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_light));
1456 } else { // Night mode disabled by default.
1457 // Set the icon according to the theme.
1458 if (MainWebViewActivity.darkTheme) {
1459 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_dark));
1461 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_light));
1465 // Show the night mode TextView.
1466 nightModeTextView.setVisibility(View.VISIBLE);
1469 case DomainsDatabaseHelper.NIGHT_MODE_ENABLED:
1470 // Set the icon according to the theme.
1471 if (MainWebViewActivity.darkTheme) {
1472 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_dark));
1474 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_light));
1477 // Hide `nightModeTextView`.
1478 nightModeTextView.setVisibility(View.GONE);
1481 case DomainsDatabaseHelper.NIGHT_MODE_DISABLED:
1482 // Set the icon according to the theme.
1483 if (MainWebViewActivity.darkTheme) {
1484 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_dark));
1486 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_light));
1489 // Hide `nightModeTextView`.
1490 nightModeTextView.setVisibility(View.GONE);
1494 // Create a `boolean` to store the current night mode setting.
1495 boolean currentNightModeEnabled = (position == DomainsDatabaseHelper.NIGHT_MODE_ENABLED) || ((position == DomainsDatabaseHelper.NIGHT_MODE_SYSTEM_DEFAULT) && defaultNightModeBoolean);
1497 // Disable the JavaScript `Switch` if night mode is enabled.
1498 if (currentNightModeEnabled) {
1499 javaScriptEnabledSwitch.setEnabled(false);
1501 javaScriptEnabledSwitch.setEnabled(true);
1504 // Update the JavaScript icon.
1505 if ((javaScriptEnabledInt == 1) || currentNightModeEnabled) {
1506 javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.javascript_enabled));
1508 javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.privacy_mode));
1511 // Update the DOM storage status.
1512 if ((javaScriptEnabledInt == 1) || currentNightModeEnabled) { // JavaScript is enabled.
1513 // Enable the DOM storage `Switch`.
1514 domStorageEnabledSwitch.setEnabled(true);
1516 // Set the DOM storage status. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
1517 if (domStorageEnabledInt == 1) { // Both JavaScript and DOM storage are enabled.
1518 domStorageEnabledSwitch.setChecked(true);
1519 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_enabled));
1520 } else { // JavaScript is enabled but DOM storage is disabled.
1521 // Set the DOM storage switch to off.
1522 domStorageEnabledSwitch.setChecked(false);
1524 // Set the icon according to the theme.
1525 if (MainWebViewActivity.darkTheme) {
1526 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_dark));
1528 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_light));
1531 } else { // JavaScript is disabled.
1532 // Disable the DOM storage `Switch`.
1533 domStorageEnabledSwitch.setEnabled(false);
1535 // Set the checked status of DOM storage.
1536 if (domStorageEnabledInt == 1) { // DOM storage is enabled but JavaScript is disabled.
1537 domStorageEnabledSwitch.setChecked(true);
1538 } else { // Both JavaScript and DOM storage are disabled.
1539 domStorageEnabledSwitch.setChecked(false);
1542 // Set the icon according to the theme.
1543 if (MainWebViewActivity.darkTheme) {
1544 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_dark));
1546 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_light));
1552 public void onNothingSelected(AdapterView<?> parent) {
1557 // Set the display webpage images spinner listener.
1558 displayWebpageImagesSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1560 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1561 // Update the icon and the visibility of `displayImagesTextView`.
1563 case DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_SYSTEM_DEFAULT:
1564 if (defaultDisplayWebpageImagesBoolean) {
1565 // Set the icon according to the theme.
1566 if (MainWebViewActivity.darkTheme) {
1567 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_dark));
1569 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_light));
1572 // Set the icon according to the theme.
1573 if (MainWebViewActivity.darkTheme) {
1574 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_dark));
1576 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_light));
1580 // Show `displayImagesTextView`.
1581 displayImagesTextView.setVisibility(View.VISIBLE);
1584 case DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_ENABLED:
1585 // Set the icon according to the theme.
1586 if (MainWebViewActivity.darkTheme) {
1587 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_dark));
1589 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_light));
1592 // Hide `displayImagesTextView`.
1593 displayImagesTextView.setVisibility(View.GONE);
1596 case DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_DISABLED:
1597 // Set the icon according to the theme.
1598 if (MainWebViewActivity.darkTheme) {
1599 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_dark));
1601 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_light));
1604 // Hide `displayImagesTextView`.
1605 displayImagesTextView.setVisibility(View.GONE);
1611 public void onNothingSelected(AdapterView<?> parent) {
1616 // Set the pinned SSL certificate switch listener.
1617 pinnedSslCertificateSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1619 if (isChecked) { // Pinned SSL certificate is enabled.
1620 // Set the icon according to the theme.
1621 if (MainWebViewActivity.darkTheme) {
1622 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_dark));
1624 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_light));
1627 // Update the visibility of the saved SSL certificate.
1628 if (savedSslCertificateIssuedToCNameString == null) {
1629 savedSslCertificateLinearLayout.setVisibility(View.GONE);
1631 savedSslCertificateLinearLayout.setVisibility(View.VISIBLE);
1634 // Update the visibility of the current website SSL certificate.
1635 if (currentWebsiteSslCertificate == null) {
1636 // Hide the SSL certificate.
1637 currentWebsiteCertificateLinearLayout.setVisibility(View.GONE);
1639 // Show the instruction.
1640 noCurrentWebsiteCertificateTextView.setVisibility(View.VISIBLE);
1642 // Show the SSL certificate.
1643 currentWebsiteCertificateLinearLayout.setVisibility(View.VISIBLE);
1645 // Hide the instruction.
1646 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
1649 // Set the status of the radio buttons.
1650 if (savedSslCertificateLinearLayout.getVisibility() == View.VISIBLE) { // The saved SSL certificate is displayed.
1651 savedSslCertificateRadioButton.setChecked(true);
1652 currentWebsiteCertificateRadioButton.setChecked(false);
1653 } else if (currentWebsiteCertificateLinearLayout.getVisibility() == View.VISIBLE) { // The saved SSL certificate is hidden but the current website SSL certificate is visible.
1654 currentWebsiteCertificateRadioButton.setChecked(true);
1655 savedSslCertificateRadioButton.setChecked(false);
1656 } else { // Neither SSL certificate is visible.
1657 savedSslCertificateRadioButton.setChecked(false);
1658 currentWebsiteCertificateRadioButton.setChecked(false);
1660 } else { // Pinned SSL certificate is disabled.
1661 // Set the icon according to the theme.
1662 if (MainWebViewActivity.darkTheme) {
1663 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_dark));
1665 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_light));
1668 // Hide the SSl certificates and instructions.
1669 savedSslCertificateLinearLayout.setVisibility(View.GONE);
1670 currentWebsiteCertificateLinearLayout.setVisibility(View.GONE);
1671 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
1673 // Uncheck the radio buttons.
1674 savedSslCertificateRadioButton.setChecked(false);
1675 currentWebsiteCertificateRadioButton.setChecked(false);
1679 savedSslCertificateLinearLayout.setOnClickListener((View v) -> {
1680 savedSslCertificateRadioButton.setChecked(true);
1681 currentWebsiteCertificateRadioButton.setChecked(false);
1684 savedSslCertificateRadioButton.setOnClickListener((View v) -> {
1685 savedSslCertificateRadioButton.setChecked(true);
1686 currentWebsiteCertificateRadioButton.setChecked(false);
1689 currentWebsiteCertificateLinearLayout.setOnClickListener((View v) -> {
1690 currentWebsiteCertificateRadioButton.setChecked(true);
1691 savedSslCertificateRadioButton.setChecked(false);
1694 currentWebsiteCertificateRadioButton.setOnClickListener((View v) -> {
1695 currentWebsiteCertificateRadioButton.setChecked(true);
1696 savedSslCertificateRadioButton.setChecked(false);
1699 return domainSettingsView;
1702 private boolean checkDomainNameAgainstCertificate(String domainName, String certificateCommonName) {
1703 // Initialize `domainNamesMatch`.
1704 boolean domainNamesMatch = false;
1706 // Check various wildcard permutations if `domainName` and `certificateCommonName` are not empty.
1707 // `noinspection ConstantCondition` removes Android Studio's incorrect lint warning that `domainName` can never be `null`.
1708 //noinspection ConstantConditions
1709 if ((domainName != null) && (certificateCommonName != null)) {
1710 // Check if the domains match.
1711 if (domainName.equals(certificateCommonName)) {
1712 domainNamesMatch = true;
1715 // If `domainName` starts with a wildcard, check the base domain against all the subdomains of `certificateCommonName`.
1716 if (!domainNamesMatch && domainName.startsWith("*.") && (domainName.length() > 2)) {
1717 // Remove the initial `*.`.
1718 String baseDomainName = domainName.substring(2);
1720 // Setup a copy of `certificateCommonName` to test subdomains.
1721 String certificateCommonNameSubdomain = certificateCommonName;
1723 // Check all the subdomains in `certificateCommonNameSubdomain` against `baseDomainName`.
1724 while (!domainNamesMatch && certificateCommonNameSubdomain.contains(".")) { // Stop checking if we know that `domainNamesMatch` is `true` or if we run out of `.`.
1725 // Test the `certificateCommonNameSubdomain` against `baseDomainName`.
1726 if (certificateCommonNameSubdomain.equals(baseDomainName)) {
1727 domainNamesMatch = true;
1730 // Strip out the lowest subdomain of `certificateCommonNameSubdomain`.
1732 certificateCommonNameSubdomain = certificateCommonNameSubdomain.substring(certificateCommonNameSubdomain.indexOf(".") + 1);
1733 } catch (IndexOutOfBoundsException e) { // `certificateCommonNameSubdomain` ends with `.`.
1734 certificateCommonNameSubdomain = "";
1739 // If `certificateCommonName` starts with a wildcard, check the base common name against all the subdomains of `domainName`.
1740 if (!domainNamesMatch && certificateCommonName.startsWith("*.") && (certificateCommonName.length() > 2)) {
1741 // Remove the initial `*.`.
1742 String baseCertificateCommonName = certificateCommonName.substring(2);
1744 // Setup a copy of `domainName` to test subdomains.
1745 String domainNameSubdomain = domainName;
1747 // Check all the subdomains in `domainNameSubdomain` against `baseCertificateCommonName`.
1748 while (!domainNamesMatch && domainNameSubdomain.contains(".") && (domainNameSubdomain.length() > 2)) {
1749 // Test the `domainNameSubdomain` against `baseCertificateCommonName`.
1750 if (domainNameSubdomain.equals(baseCertificateCommonName)) {
1751 domainNamesMatch = true;
1754 // Strip out the lowest subdomain of `domainNameSubdomain`.
1756 domainNameSubdomain = domainNameSubdomain.substring(domainNameSubdomain.indexOf(".") + 1);
1757 } catch (IndexOutOfBoundsException e) { // `domainNameSubdomain` ends with `.`.
1758 domainNameSubdomain = "";
1763 // If both names start with a wildcard, check if the root of one contains the root of the other.
1764 if (!domainNamesMatch && domainName.startsWith("*.") && (domainName.length() > 2) && certificateCommonName.startsWith("*.") && (certificateCommonName.length() > 2)) {
1765 // Remove the wildcards.
1766 String rootDomainName = domainName.substring(2);
1767 String rootCertificateCommonName = certificateCommonName.substring(2);
1769 // Check if one name ends with the contents of the other. If so, there will be overlap in the their wildcard subdomains.
1770 if (rootDomainName.endsWith(rootCertificateCommonName) || rootCertificateCommonName.endsWith(rootDomainName)) {
1771 domainNamesMatch = true;
1776 return domainNamesMatch;