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 // `android.support.v4.app.Fragment` must be used until minimum API >= 23. Otherwise `getContext()` does not work.
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 defaultSwipeToRefresh = sharedPreferences.getBoolean("swipe_to_refresh", true);
99 final boolean defaultNightMode = sharedPreferences.getBoolean("night_mode", false);
100 final boolean defaultDisplayWebpageImages = sharedPreferences.getBoolean("display_webpage_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 Switch ultraPrivacySwitch = domainSettingsView.findViewById(R.id.domain_settings_ultraprivacy_switch);
124 ImageView ultraPrivacyImageView = domainSettingsView.findViewById(R.id.domain_settings_ultraprivacy_imageview);
125 Switch blockAllThirdPartyRequestsSwitch = domainSettingsView.findViewById(R.id.domain_settings_block_all_third_party_requests_switch);
126 ImageView blockAllThirdPartyRequestsImageView = domainSettingsView.findViewById(R.id.domain_settings_block_all_third_party_requests_imageview);
127 final Spinner userAgentSpinner = domainSettingsView.findViewById(R.id.domain_settings_user_agent_spinner);
128 final TextView userAgentTextView = domainSettingsView.findViewById(R.id.domain_settings_user_agent_textview);
129 final EditText customUserAgentEditText = domainSettingsView.findViewById(R.id.domain_settings_custom_user_agent_edittext);
130 final Spinner fontSizeSpinner = domainSettingsView.findViewById(R.id.domain_settings_font_size_spinner);
131 final TextView fontSizeTextView = domainSettingsView.findViewById(R.id.domain_settings_font_size_textview);
132 final ImageView swipeToRefreshImageView = domainSettingsView.findViewById(R.id.domain_settings_swipe_to_refresh_imageview);
133 final Spinner swipeToRefreshSpinner = domainSettingsView.findViewById(R.id.domain_settings_swipe_to_refresh_spinner);
134 final TextView swipeToRefreshTextView = domainSettingsView.findViewById(R.id.domain_settings_swipe_to_refresh_textview);
135 final ImageView nightModeImageView = domainSettingsView.findViewById(R.id.domain_settings_night_mode_imageview);
136 final Spinner nightModeSpinner = domainSettingsView.findViewById(R.id.domain_settings_night_mode_spinner);
137 final TextView nightModeTextView = domainSettingsView.findViewById(R.id.domain_settings_night_mode_textview);
138 final ImageView displayWebpageImagesImageView = domainSettingsView.findViewById(R.id.domain_settings_display_webpage_images_imageview);
139 final Spinner displayWebpageImagesSpinner = domainSettingsView.findViewById(R.id.domain_settings_display_webpage_images_spinner);
140 final TextView displayImagesTextView = domainSettingsView.findViewById(R.id.domain_settings_display_webpage_images_textview);
141 final ImageView pinnedSslCertificateImageView = domainSettingsView.findViewById(R.id.domain_settings_pinned_ssl_certificate_imageview);
142 Switch pinnedSslCertificateSwitch = domainSettingsView.findViewById(R.id.domain_settings_pinned_ssl_certificate_switch);
143 final LinearLayout savedSslCertificateLinearLayout = domainSettingsView.findViewById(R.id.saved_ssl_certificate_linearlayout);
144 final RadioButton savedSslCertificateRadioButton = domainSettingsView.findViewById(R.id.saved_ssl_certificate_radiobutton);
145 final TextView savedSslCertificateIssuedToCNameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_to_cname);
146 TextView savedSslCertificateIssuedToONameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_to_oname);
147 TextView savedSslCertificateIssuedToUNameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_to_uname);
148 TextView savedSslCertificateIssuedByCNameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_by_cname);
149 TextView savedSslCertificateIssuedByONameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_by_oname);
150 TextView savedSslCertificateIssuedByUNameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_by_uname);
151 TextView savedSslCertificateStartDateTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_start_date);
152 TextView savedSslCertificateEndDateTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_end_date);
153 final LinearLayout currentWebsiteCertificateLinearLayout = domainSettingsView.findViewById(R.id.current_website_certificate_linearlayout);
154 final RadioButton currentWebsiteCertificateRadioButton = domainSettingsView.findViewById(R.id.current_website_certificate_radiobutton);
155 final TextView currentWebsiteCertificateIssuedToCNameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_to_cname);
156 TextView currentWebsiteCertificateIssuedToONameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_to_oname);
157 TextView currentWebsiteCertificateIssuedToUNameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_to_uname);
158 TextView currentWebsiteCertificateIssuedByCNameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_by_cname);
159 TextView currentWebsiteCertificateIssuedByONameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_by_oname);
160 TextView currentWebsiteCertificateIssuedByUNameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_by_uname);
161 TextView currentWebsiteCertificateStartDateTextView = domainSettingsView.findViewById(R.id.current_website_certificate_start_date);
162 TextView currentWebsiteCertificateEndDateTextView = domainSettingsView.findViewById(R.id.current_website_certificate_end_date);
163 final TextView noCurrentWebsiteCertificateTextView = domainSettingsView.findViewById(R.id.no_current_website_certificate);
165 // Setup the SSL certificate labels.
166 final String cNameLabel = getString(R.string.common_name) + " ";
167 String oNameLabel = getString(R.string.organization) + " ";
168 String uNameLabel = getString(R.string.organizational_unit) + " ";
169 String startDateLabel = getString(R.string.start_date) + " ";
170 String endDateLabel = getString(R.string.end_date) + " ";
172 // Get the current website SSL certificate
173 final SslCertificate currentWebsiteSslCertificate = MainWebViewActivity.sslCertificate;
175 // Initialize the database handler. The `0` specifies the database version, but that is ignored and set instead using a constant in `DomainsDatabaseHelper`.
176 DomainsDatabaseHelper domainsDatabaseHelper = new DomainsDatabaseHelper(context, null, null, 0);
178 // Get the database `Cursor` for this ID and move it to the first row.
179 Cursor domainCursor = domainsDatabaseHelper.getCursorForId(databaseId);
180 domainCursor.moveToFirst();
182 // Save the `Cursor` entries as variables.
183 String domainNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.DOMAIN_NAME));
184 final int javaScriptEnabledInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_JAVASCRIPT));
185 int firstPartyCookiesEnabledInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FIRST_PARTY_COOKIES));
186 int thirdPartyCookiesEnabledInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_THIRD_PARTY_COOKIES));
187 final int domStorageEnabledInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_DOM_STORAGE));
188 int formDataEnabledInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FORM_DATA)); // Form data can be remove once the minimum API >= 26.
189 int easyListEnabledInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_EASYLIST));
190 int easyPrivacyEnabledInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_EASYPRIVACY));
191 int fanboysAnnoyanceListInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FANBOYS_ANNOYANCE_LIST));
192 int fanboysSocialBlockingListInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FANBOYS_SOCIAL_BLOCKING_LIST));
193 int ultraPrivacyEnabledInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_ULTRAPRIVACY));
194 int blockAllThirdPartyRequestsInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.BLOCK_ALL_THIRD_PARTY_REQUESTS));
195 final String currentUserAgentName = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.USER_AGENT));
196 int fontSizeInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.FONT_SIZE));
197 int swipeToRefreshInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.SWIPE_TO_REFRESH));
198 int nightModeInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.NIGHT_MODE));
199 int displayImagesInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.DISPLAY_IMAGES));
200 int pinnedSslCertificateInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.PINNED_SSL_CERTIFICATE));
201 final String savedSslCertificateIssuedToCNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_TO_COMMON_NAME));
202 String savedSslCertificateIssuedToONameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_TO_ORGANIZATION));
203 String savedSslCertificateIssuedToUNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_TO_ORGANIZATIONAL_UNIT));
204 String savedSslCertificateIssuedByCNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_BY_COMMON_NAME));
205 String savedSslCertificateIssuedByONameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_BY_ORGANIZATION));
206 String savedSslCertificateIssuedByUNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_BY_ORGANIZATIONAL_UNIT));
208 // Initialize the saved SSL certificate date variables.
209 Date savedSslCertificateStartDate = null;
210 Date savedSslCertificateEndDate = null;
212 // Only get the saved SSL certificate dates from the cursor if they are not set to `0`.
213 if (domainCursor.getLong(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_START_DATE)) != 0) {
214 savedSslCertificateStartDate = new Date(domainCursor.getLong(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_START_DATE)));
217 if (domainCursor.getLong(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_END_DATE)) != 0) {
218 savedSslCertificateEndDate = new Date(domainCursor.getLong(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_END_DATE)));
221 // Create array adapters for the spinners.
222 ArrayAdapter<CharSequence> translatedUserAgentArrayAdapter = ArrayAdapter.createFromResource(context, R.array.translated_domain_settings_user_agent_names, R.layout.spinner_item);
223 ArrayAdapter<CharSequence> fontSizeArrayAdapter = ArrayAdapter.createFromResource(context, R.array.domain_settings_font_size_entries, R.layout.spinner_item);
224 ArrayAdapter<CharSequence> fontSizeEntryValuesArrayAdapter = ArrayAdapter.createFromResource(context, R.array.domain_settings_font_size_entry_values, R.layout.spinner_item);
225 ArrayAdapter<CharSequence> swipeToRefreshArrayAdapter = ArrayAdapter.createFromResource(context, R.array.swipe_to_refresh_array, R.layout.spinner_item);
226 ArrayAdapter<CharSequence> nightModeArrayAdapter = ArrayAdapter.createFromResource(context, R.array.night_mode_array, R.layout.spinner_item);
227 ArrayAdapter<CharSequence> displayImagesArrayAdapter = ArrayAdapter.createFromResource(context, R.array.display_webpage_images_array, R.layout.spinner_item);
229 // Set the drop down view resource on the spinners.
230 translatedUserAgentArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items);
231 fontSizeArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items);
232 swipeToRefreshArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items);
233 nightModeArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items);
234 displayImagesArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items);
236 // Set the array adapters for the spinners.
237 userAgentSpinner.setAdapter(translatedUserAgentArrayAdapter);
238 fontSizeSpinner.setAdapter(fontSizeArrayAdapter);
239 swipeToRefreshSpinner.setAdapter(swipeToRefreshArrayAdapter);
240 nightModeSpinner.setAdapter(nightModeArrayAdapter);
241 displayWebpageImagesSpinner.setAdapter(displayImagesArrayAdapter);
243 // Create a spannable string builder for each TextView that needs multiple colors of text.
244 SpannableStringBuilder savedSslCertificateIssuedToCNameStringBuilder = new SpannableStringBuilder(cNameLabel + savedSslCertificateIssuedToCNameString);
245 SpannableStringBuilder savedSslCertificateIssuedToONameStringBuilder = new SpannableStringBuilder(oNameLabel + savedSslCertificateIssuedToONameString);
246 SpannableStringBuilder savedSslCertificateIssuedToUNameStringBuilder = new SpannableStringBuilder(uNameLabel + savedSslCertificateIssuedToUNameString);
247 SpannableStringBuilder savedSslCertificateIssuedByCNameStringBuilder = new SpannableStringBuilder(cNameLabel + savedSslCertificateIssuedByCNameString);
248 SpannableStringBuilder savedSslCertificateIssuedByONameStringBuilder = new SpannableStringBuilder(oNameLabel + savedSslCertificateIssuedByONameString);
249 SpannableStringBuilder savedSslCertificateIssuedByUNameStringBuilder = new SpannableStringBuilder(uNameLabel + savedSslCertificateIssuedByUNameString);
251 // Initialize the `SpannableStringBuilders` for the SSL certificate dates.
252 SpannableStringBuilder savedSslCertificateStartDateStringBuilder;
253 SpannableStringBuilder savedSslCertificateEndDateStringBuilder;
255 // Leave the SSL certificate dates empty if they are `null`.
256 if (savedSslCertificateStartDate == null) {
257 savedSslCertificateStartDateStringBuilder = new SpannableStringBuilder(startDateLabel);
259 savedSslCertificateStartDateStringBuilder = new SpannableStringBuilder(startDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(savedSslCertificateStartDate));
262 if (savedSslCertificateEndDate == null) {
263 savedSslCertificateEndDateStringBuilder = new SpannableStringBuilder(endDateLabel);
265 savedSslCertificateEndDateStringBuilder = new SpannableStringBuilder(endDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(savedSslCertificateEndDate));
268 // Create a red `ForegroundColorSpan`. We have to use the deprecated `getColor` until API >= 23.
269 final ForegroundColorSpan redColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.red_a700));
271 // Create a blue `ForegroundColorSpan`.
272 final ForegroundColorSpan blueColorSpan;
274 // Set `blueColorSpan` according to the theme. We have to use the deprecated `getColor()` until API >= 23.
275 if (MainWebViewActivity.darkTheme) {
276 //noinspection deprecation
277 blueColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.blue_400));
279 //noinspection deprecation
280 blueColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.blue_700));
283 // Set the domain name from the the database cursor.
284 domainNameEditText.setText(domainNameString);
286 // Update the certificates' `Common Name` color when the domain name text changes.
287 domainNameEditText.addTextChangedListener(new TextWatcher() {
289 public void beforeTextChanged(CharSequence s, int start, int count, int after) {
294 public void onTextChanged(CharSequence s, int start, int before, int count) {
299 public void afterTextChanged(Editable s) {
300 // Get the new domain name.
301 String newDomainName = domainNameEditText.getText().toString();
303 // Check the saved SSL certificate against the new domain name.
304 boolean savedSslCertificateMatchesNewDomainName = checkDomainNameAgainstCertificate(newDomainName, savedSslCertificateIssuedToCNameString);
306 // Create a `SpannableStringBuilder` for the saved certificate `Common Name`.
307 SpannableStringBuilder savedSslCertificateCommonNameStringBuilder = new SpannableStringBuilder(cNameLabel + savedSslCertificateIssuedToCNameString);
309 // Format the saved certificate `Common Name` color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
310 if (savedSslCertificateMatchesNewDomainName) {
311 savedSslCertificateCommonNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), savedSslCertificateCommonNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
313 savedSslCertificateCommonNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), savedSslCertificateCommonNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
316 // Update `savedSslCertificateIssuedToCNameTextView`.
317 savedSslCertificateIssuedToCNameTextView.setText(savedSslCertificateCommonNameStringBuilder);
319 // Update the current website certificate if it exists.
320 if (currentWebsiteSslCertificate != null) {
321 // Get the current website certificate `Common Name`.
322 String currentWebsiteCertificateCommonName = currentWebsiteSslCertificate.getIssuedTo().getCName();
324 // Check the current website certificate against the new domain name.
325 boolean currentWebsiteCertificateMatchesNewDomainName = checkDomainNameAgainstCertificate(newDomainName, currentWebsiteCertificateCommonName);
327 // Create a `SpannableStringBuilder` for the current website certificate `Common Name`.
328 SpannableStringBuilder currentWebsiteCertificateCommonNameStringBuilder = new SpannableStringBuilder(cNameLabel + currentWebsiteCertificateCommonName);
330 // Format the current certificate `Common Name` color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
331 if (currentWebsiteCertificateMatchesNewDomainName) {
332 currentWebsiteCertificateCommonNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), currentWebsiteCertificateCommonNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
334 currentWebsiteCertificateCommonNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), currentWebsiteCertificateCommonNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
337 // Update `currentWebsiteCertificateIssuedToCNameTextView`.
338 currentWebsiteCertificateIssuedToCNameTextView.setText(currentWebsiteCertificateCommonNameStringBuilder);
343 // Create a `boolean` to track if night mode is enabled.
344 boolean nightModeEnabled = (nightModeInt == DomainsDatabaseHelper.NIGHT_MODE_ENABLED) || ((nightModeInt == DomainsDatabaseHelper.NIGHT_MODE_SYSTEM_DEFAULT) && defaultNightMode);
346 // Disable the JavaScript switch if night mode is enabled.
347 if (nightModeEnabled) {
348 javaScriptEnabledSwitch.setEnabled(false);
350 javaScriptEnabledSwitch.setEnabled(true);
353 // Set the JavaScript icon.
354 if ((javaScriptEnabledInt == 1) || nightModeEnabled) {
355 javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.javascript_enabled));
357 javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.privacy_mode));
360 // Set the JavaScript switch status.
361 if (javaScriptEnabledInt == 1) { // JavaScript is enabled.
362 javaScriptEnabledSwitch.setChecked(true);
363 } else { // JavaScript is disabled.
364 javaScriptEnabledSwitch.setChecked(false);
367 // 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.
368 if (firstPartyCookiesEnabledInt == 1) { // First-party cookies are enabled.
369 firstPartyCookiesEnabledSwitch.setChecked(true);
370 firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_enabled));
371 } else { // First-party cookies are disabled.
372 firstPartyCookiesEnabledSwitch.setChecked(false);
374 // Set the icon according to the theme.
375 if (MainWebViewActivity.darkTheme) {
376 firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_dark));
378 firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_light));
382 // Only display third-party cookies if SDK_INT >= 21.
383 if (Build.VERSION.SDK_INT >= 21) { // Third-party cookies can be configured for API >= 21.
384 // Only enable third-party-cookies if first-party cookies are enabled.
385 if (firstPartyCookiesEnabledInt == 1) { // First-party cookies are enabled.
386 // 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.
387 if (thirdPartyCookiesEnabledInt == 1) { // Both first-party and third-party cookies are enabled.
388 thirdPartyCookiesEnabledSwitch.setChecked(true);
389 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_warning));
390 } else { // First party cookies are enabled but third-party cookies are disabled.
391 thirdPartyCookiesEnabledSwitch.setChecked(false);
393 // Set the icon according to the theme.
394 if (MainWebViewActivity.darkTheme) {
395 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_dark));
397 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_light));
400 } else { // First-party cookies are disabled.
401 // Set the status of third-party cookies.
402 if (thirdPartyCookiesEnabledInt == 1) {
403 thirdPartyCookiesEnabledSwitch.setChecked(true);
405 thirdPartyCookiesEnabledSwitch.setChecked(false);
408 // Disable the third-party cookies switch.
409 thirdPartyCookiesEnabledSwitch.setEnabled(false);
411 // Set the icon according to the theme.
412 if (MainWebViewActivity.darkTheme) {
413 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_ghosted_dark));
415 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_ghosted_light));
418 } else { // Third-party cookies cannot be configured for API <= 21.
419 // Hide the LinearLayout for third-party cookies.
420 thirdPartyCookiesLinearLayout.setVisibility(View.GONE);
423 // Only enable DOM storage if JavaScript is enabled.
424 if ((javaScriptEnabledInt == 1) || nightModeEnabled) { // JavaScript is enabled.
425 // Enable the DOM storage `Switch`.
426 domStorageEnabledSwitch.setEnabled(true);
428 // Set the DOM storage status. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
429 if (domStorageEnabledInt == 1) { // Both JavaScript and DOM storage are enabled.
430 domStorageEnabledSwitch.setChecked(true);
431 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_enabled));
432 } else { // JavaScript is enabled but DOM storage is disabled.
433 // Set the DOM storage switch to off.
434 domStorageEnabledSwitch.setChecked(false);
436 // Set the icon according to the theme.
437 if (MainWebViewActivity.darkTheme) {
438 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_dark));
440 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_light));
443 } else { // JavaScript is disabled.
444 // Disable the DOM storage `Switch`.
445 domStorageEnabledSwitch.setEnabled(false);
447 // Set the checked status of DOM storage.
448 if (domStorageEnabledInt == 1) { // DOM storage is enabled but JavaScript is disabled.
449 domStorageEnabledSwitch.setChecked(true);
450 } else { // Both JavaScript and DOM storage are disabled.
451 domStorageEnabledSwitch.setChecked(false);
454 // Set the icon according to the theme.
455 if (MainWebViewActivity.darkTheme) {
456 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_dark));
458 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_light));
462 // 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.
463 if (Build.VERSION.SDK_INT >= 26) { // Form data no longer applies to newer versions of Android.
464 // Hide the form data switch.
465 formDataEnabledSwitch.setVisibility(View.GONE);
466 } else { // Form data should be displayed because this is an older version of Android.
467 if (formDataEnabledInt == 1) { // Form data is on.
468 formDataEnabledSwitch.setChecked(true);
469 formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_enabled));
470 } else { // Form data is off.
471 // Turn the form data switch to off.
472 formDataEnabledSwitch.setChecked(false);
474 // Set the icon according to the theme.
475 if (MainWebViewActivity.darkTheme) {
476 formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_disabled_dark));
478 formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_disabled_light));
483 // Set the EasyList status. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
484 if (easyListEnabledInt == 1) { // EasyList is on.
485 // Turn the switch on.
486 easyListSwitch.setChecked(true);
488 // Set the icon according to the theme.
489 if (MainWebViewActivity.darkTheme) {
490 easyListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_enabled_dark));
492 easyListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_enabled_light));
494 } else { // EasyList is off.
495 // Turn the switch off.
496 easyListSwitch.setChecked(false);
498 // Set the icon according to the theme.
499 if (MainWebViewActivity.darkTheme) {
500 easyListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_disabled_dark));
502 easyListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_disabled_light));
506 // Set the EasyPrivacy status. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
507 if (easyPrivacyEnabledInt == 1) { // EasyPrivacy is on.
508 // Turn the switch on.
509 easyPrivacySwitch.setChecked(true);
511 // Set the icon according to the theme.
512 if (MainWebViewActivity.darkTheme) {
513 easyPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_enabled_dark));
515 easyPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_enabled_light));
517 } else { // EasyPrivacy is off.
518 // Turn the switch off.
519 easyPrivacySwitch.setChecked(false);
521 // Set the icon according to the theme.
522 if (MainWebViewActivity.darkTheme) {
523 easyPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_disabled_dark));
525 easyPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_disabled_light));
529 // 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.
530 if (fanboysAnnoyanceListInt == 1) { // Fanboy's Annoyance List is on.
531 // Turn the switch on.
532 fanboysAnnoyanceListSwitch.setChecked(true);
534 // Set the icon according to the theme.
535 if (MainWebViewActivity.darkTheme) {
536 fanboysAnnoyanceListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_dark));
538 fanboysAnnoyanceListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_light));
540 } else { // Fanboy's Annoyance List is off.
541 // Turn the switch off.
542 fanboysAnnoyanceListSwitch.setChecked(false);
544 // Set the icon according to the theme.
545 if (MainWebViewActivity.darkTheme) {
546 fanboysAnnoyanceListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_dark));
548 fanboysAnnoyanceListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_light));
552 // Only enable Fanboy's Social Blocking List if Fanboy's Annoyance List is off.
553 if (fanboysAnnoyanceListInt == 0) { // Fanboy's Annoyance List is on.
554 // 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.
555 if (fanboysSocialBlockingListInt == 1) { // Fanboy's Social Blocking List is on.
556 // Enable the switch and turn it on.
557 fanboysSocialBlockingListSwitch.setEnabled(true);
558 fanboysSocialBlockingListSwitch.setChecked(true);
560 // Set the icon according to the theme.
561 if (MainWebViewActivity.darkTheme) {
562 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_dark));
564 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_light));
566 } else { // Fanboy's Social Blocking List is off.
567 // Enable the switch but turn it off.
568 fanboysSocialBlockingListSwitch.setEnabled(true);
569 fanboysSocialBlockingListSwitch.setChecked(false);
571 // Set the icon according to the theme.
572 if (MainWebViewActivity.darkTheme) {
573 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_dark));
575 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_light));
578 } else { // Fanboy's Annoyance List is on.
579 // 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.
580 if (fanboysSocialBlockingListInt == 1) { // Fanboy's Social Blocking List is on.
581 // Disable the switch but turn it on.
582 fanboysSocialBlockingListSwitch.setEnabled(false);
583 fanboysSocialBlockingListSwitch.setChecked(true);
584 } else { // Fanboy's Social Blocking List is off.
585 // Disable the switch and turn it off.
586 fanboysSocialBlockingListSwitch.setEnabled(false);
587 fanboysSocialBlockingListSwitch.setChecked(false);
590 // Set the icon according to the theme.
591 if (MainWebViewActivity.darkTheme) {
592 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_ghosted_dark));
594 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_ghosted_light));
598 // Set the UltraPrivacy status. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
599 if (ultraPrivacyEnabledInt == 1) { // UltraPrivacy is on.
600 // Turn the switch on.
601 ultraPrivacySwitch.setChecked(true);
603 // Set the icon according to the theme.
604 if (MainWebViewActivity.darkTheme) {
605 ultraPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_enabled_dark));
607 ultraPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_enabled_light));
609 } else { // EasyPrivacy is off.
610 // Turn the switch off.
611 ultraPrivacySwitch.setChecked(false);
613 // Set the icon according to the theme.
614 if (MainWebViewActivity.darkTheme) {
615 ultraPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_disabled_dark));
617 ultraPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_disabled_light));
621 // Set the third-party resource blocking status. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
622 if (blockAllThirdPartyRequestsInt == 1) { // Blocking all third-party requests is on.
623 // Turn the switch on.
624 blockAllThirdPartyRequestsSwitch.setChecked(true);
626 // Set the icon according to the theme.
627 if (MainWebViewActivity.darkTheme) {
628 blockAllThirdPartyRequestsImageView.setImageDrawable(resources.getDrawable(R.drawable.block_all_third_party_requests_enabled_dark));
630 blockAllThirdPartyRequestsImageView.setImageDrawable(resources.getDrawable(R.drawable.block_all_third_party_requests_enabled_light));
632 } else { // Blocking all third-party requests is off.
633 // Turn the switch off.
634 blockAllThirdPartyRequestsSwitch.setChecked(false);
636 // Set the icon according to the theme.
637 if (MainWebViewActivity.darkTheme) {
638 blockAllThirdPartyRequestsImageView.setImageDrawable(resources.getDrawable(R.drawable.block_all_third_party_requests_disabled_dark));
640 blockAllThirdPartyRequestsImageView.setImageDrawable(resources.getDrawable(R.drawable.block_all_third_party_requests_disabled_light));
644 // Inflated a WebView to get the default user agent.
645 // `@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.
646 @SuppressLint("InflateParams") View bareWebViewLayout = inflater.inflate(R.layout.bare_webview, null, false);
647 WebView bareWebView = bareWebViewLayout.findViewById(R.id.bare_webview);
648 final String webViewDefaultUserAgentString = bareWebView.getSettings().getUserAgentString();
650 // Get a handle for the user agent array adapter. This array does not contain the `System default` entry.
651 ArrayAdapter<CharSequence> userAgentNamesArray = ArrayAdapter.createFromResource(context, R.array.user_agent_names, R.layout.spinner_item);
653 // Get the positions of the user agent and the default user agent.
654 int userAgentArrayPosition = userAgentNamesArray.getPosition(currentUserAgentName);
655 int defaultUserAgentArrayPosition = userAgentNamesArray.getPosition(defaultUserAgentName);
657 // Get a handle for the user agent data array. This array does not contain the `System default` entry.
658 String[] userAgentDataArray = resources.getStringArray(R.array.user_agent_data);
660 // Set the user agent text.
661 if (currentUserAgentName.equals(getString(R.string.system_default_user_agent))) { // Use the system default user agent.
662 // Set the user agent according to the system default.
663 switch (defaultUserAgentArrayPosition) {
664 case MainWebViewActivity.UNRECOGNIZED_USER_AGENT: // The default user agent name is not on the canonical list.
665 // This is probably because it was set in an older version of Privacy Browser before the switch to persistent user agent names.
666 userAgentTextView.setText(defaultUserAgentName);
669 case MainWebViewActivity.SETTINGS_WEBVIEW_DEFAULT_USER_AGENT:
670 // Display the `WebView` default user agent.
671 userAgentTextView.setText(webViewDefaultUserAgentString);
674 case MainWebViewActivity.SETTINGS_CUSTOM_USER_AGENT:
675 // Display the custom user agent.
676 userAgentTextView.setText(defaultCustomUserAgentString);
680 // Get the user agent string from the user agent data array.
681 userAgentTextView.setText(userAgentDataArray[defaultUserAgentArrayPosition]);
683 } else if (userAgentArrayPosition == MainWebViewActivity.UNRECOGNIZED_USER_AGENT) { // A custom user agent is stored in the current user agent name.
684 // Set the user agent spinner to `Custom user agent`.
685 userAgentSpinner.setSelection(MainWebViewActivity.DOMAINS_CUSTOM_USER_AGENT);
687 // Hide the user agent TextView.
688 userAgentTextView.setVisibility(View.GONE);
690 // Show the custom user agent EditText and set the current user agent name as the text.
691 customUserAgentEditText.setVisibility(View.VISIBLE);
692 customUserAgentEditText.setText(currentUserAgentName);
693 } else { // The user agent name contains one of the canonical user agents.
694 // 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.
695 userAgentSpinner.setSelection(userAgentArrayPosition + 1);
697 // Show the user agent TextView.
698 userAgentTextView.setVisibility(View.VISIBLE);
700 // Hide the custom user agent EditText.
701 customUserAgentEditText.setVisibility(View.GONE);
703 // Set the user agent text.
704 switch (userAgentArrayPosition) {
705 case MainWebViewActivity.DOMAINS_WEBVIEW_DEFAULT_USER_AGENT:
706 // Display the WebView default user agent.
707 userAgentTextView.setText(webViewDefaultUserAgentString);
711 // 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.
712 userAgentTextView.setText(userAgentDataArray[userAgentArrayPosition + 1]);
716 // Open the user agent spinner when the TextView is clicked.
717 userAgentTextView.setOnClickListener((View v) -> {
718 // Open the user agent spinner.
719 userAgentSpinner.performClick();
722 // Set the selected font size.
723 int fontSizeArrayPosition = fontSizeEntryValuesArrayAdapter.getPosition(String.valueOf(fontSizeInt));
724 fontSizeSpinner.setSelection(fontSizeArrayPosition);
726 // Set the default font size text.
727 int defaultFontSizeArrayPosition = fontSizeEntryValuesArrayAdapter.getPosition(defaultFontSizeString);
728 fontSizeTextView.setText(fontSizeArrayAdapter.getItem(defaultFontSizeArrayPosition));
730 // Set the display options for the font size TextView.
731 if (fontSizeArrayPosition == 0) { // System default font size is selected. Display `fontSizeTextView`.
732 fontSizeTextView.setVisibility(View.VISIBLE);
733 } else { // A custom font size is specified. Hide `fontSizeTextView`.
734 fontSizeTextView.setVisibility(View.GONE);
737 // Open the font size spinner when the TextView is clicked.
738 fontSizeTextView.setOnClickListener((View v) -> {
739 // Open the user agent spinner.
740 fontSizeSpinner.performClick();
743 // Display the swipe to refresh selection in the spinner.
744 swipeToRefreshSpinner.setSelection(swipeToRefreshInt);
746 // Set the swipe to refresh text.
747 if (defaultSwipeToRefresh) {
748 swipeToRefreshTextView.setText(swipeToRefreshArrayAdapter.getItem(DomainsDatabaseHelper.SWIPE_TO_REFRESH_ENABLED));
750 swipeToRefreshTextView.setText(swipeToRefreshArrayAdapter.getItem(DomainsDatabaseHelper.SWIPE_TO_REFRESH_DISABLED));
753 // 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.
754 switch (swipeToRefreshInt) {
755 case DomainsDatabaseHelper.SWIPE_TO_REFRESH_SYSTEM_DEFAULT:
756 if (defaultSwipeToRefresh) { // Swipe to refresh is enabled by default.
757 // Set the icon according to the theme.
758 if (MainWebViewActivity.darkTheme) {
759 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_enabled_dark));
761 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_enabled_light));
763 } else { // Swipe to refresh is disabled by default
764 // Set the icon according to the theme.
765 if (MainWebViewActivity.darkTheme) {
766 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_disabled_dark));
768 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_disabled_light));
772 // Show the swipe to refresh TextView.
773 swipeToRefreshTextView.setVisibility(View.VISIBLE);
776 case DomainsDatabaseHelper.SWIPE_TO_REFRESH_ENABLED:
777 // Set the icon according to the theme.
778 if (MainWebViewActivity.darkTheme) {
779 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_enabled_dark));
781 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_enabled_light));
784 // Hide the swipe to refresh TextView.`
785 swipeToRefreshTextView.setVisibility(View.GONE);
788 case DomainsDatabaseHelper.SWIPE_TO_REFRESH_DISABLED:
789 // Set the icon according to the theme.
790 if (MainWebViewActivity.darkTheme) {
791 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_disabled_dark));
793 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_disabled_light));
796 // Hide the swipe to refresh TextView.
797 swipeToRefreshTextView.setVisibility(View.GONE);
800 // Open the swipe to refresh spinner when the TextView is clicked.
801 swipeToRefreshTextView.setOnClickListener((View v) -> {
802 // Open the swipe to refresh spinner.
803 swipeToRefreshSpinner.performClick();
806 // Display the night mode in the spinner.
807 nightModeSpinner.setSelection(nightModeInt);
809 // Set the default night mode text.
810 if (defaultNightMode) {
811 nightModeTextView.setText(nightModeArrayAdapter.getItem(DomainsDatabaseHelper.NIGHT_MODE_ENABLED));
813 nightModeTextView.setText(nightModeArrayAdapter.getItem(DomainsDatabaseHelper.NIGHT_MODE_DISABLED));
816 // 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.
817 switch (nightModeInt) {
818 case DomainsDatabaseHelper.NIGHT_MODE_SYSTEM_DEFAULT:
819 if (defaultNightMode) { // Night mode enabled by default.
820 // Set the icon according to the theme.
821 if (MainWebViewActivity.darkTheme) {
822 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_dark));
824 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_light));
826 } else { // Night mode disabled by default.
827 // Set the icon according to the theme.
828 if (MainWebViewActivity.darkTheme) {
829 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_dark));
831 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_light));
835 // Show night mode TextView.
836 nightModeTextView.setVisibility(View.VISIBLE);
839 case DomainsDatabaseHelper.NIGHT_MODE_ENABLED:
840 // Set the icon according to the theme.
841 if (MainWebViewActivity.darkTheme) {
842 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_dark));
844 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_light));
847 // Hide the night mode TextView.
848 nightModeTextView.setVisibility(View.GONE);
851 case DomainsDatabaseHelper.NIGHT_MODE_DISABLED:
852 // Set the icon according to the theme.
853 if (MainWebViewActivity.darkTheme) {
854 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_dark));
856 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_light));
859 // Hide the night mode TextView.
860 nightModeTextView.setVisibility(View.GONE);
864 // Open the night mode spinner when the TextView is clicked.
865 nightModeTextView.setOnClickListener((View v) -> {
866 // Open the night mode spinner.
867 nightModeSpinner.performClick();
870 // Display the website images mode in the spinner.
871 displayWebpageImagesSpinner.setSelection(displayImagesInt);
873 // Set the default display images text.
874 if (defaultDisplayWebpageImages) {
875 displayImagesTextView.setText(displayImagesArrayAdapter.getItem(DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_ENABLED));
877 displayImagesTextView.setText(displayImagesArrayAdapter.getItem(DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_DISABLED));
880 // 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.
881 switch (displayImagesInt) {
882 case DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_SYSTEM_DEFAULT:
883 if (defaultDisplayWebpageImages) { // Display webpage images enabled by default.
884 // Set the icon according to the theme.
885 if (MainWebViewActivity.darkTheme) {
886 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_dark));
888 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_light));
890 } else { // Display webpage images disabled by default.
891 // Set the icon according to the theme.
892 if (MainWebViewActivity.darkTheme) {
893 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_dark));
895 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_light));
899 // Show the display images TextView.
900 displayImagesTextView.setVisibility(View.VISIBLE);
903 case DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_ENABLED:
904 // Set the icon according to the theme.
905 if (MainWebViewActivity.darkTheme) {
906 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_dark));
908 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_light));
911 // Hide the display images TextView.
912 displayImagesTextView.setVisibility(View.GONE);
915 case DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_DISABLED:
916 // Set the icon according to the theme.
917 if (MainWebViewActivity.darkTheme) {
918 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_dark));
920 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_light));
923 // Hide the display images TextView.
924 displayImagesTextView.setVisibility(View.GONE);
928 // Open the display images spinner when the TextView is clicked.
929 displayImagesTextView.setOnClickListener((View v) -> {
930 // Open the user agent spinner.
931 displayWebpageImagesSpinner.performClick();
934 // Set the pinned SSL certificate icon.
935 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.
937 pinnedSslCertificateSwitch.setChecked(true);
939 // Set the icon according to the theme.
940 if (MainWebViewActivity.darkTheme) {
941 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_dark));
943 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_light));
945 } else { // Pinned SSL certificate is disabled.
946 // Uncheck the switch.
947 pinnedSslCertificateSwitch.setChecked(false);
949 // Set the icon according to the theme.
950 if (MainWebViewActivity.darkTheme) {
951 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_dark));
953 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_light));
957 // Store the current date.
958 Date currentDate = Calendar.getInstance().getTime();
960 // Setup the `StringBuilders` to display the general certificate information in blue. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
961 savedSslCertificateIssuedToONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), savedSslCertificateIssuedToONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
962 savedSslCertificateIssuedToUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), savedSslCertificateIssuedToUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
963 savedSslCertificateIssuedByCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), savedSslCertificateIssuedByCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
964 savedSslCertificateIssuedByONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), savedSslCertificateIssuedByONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
965 savedSslCertificateIssuedByUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), savedSslCertificateIssuedByUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
967 // Check the certificate `Common Name` against the domain name.
968 boolean savedSSlCertificateCommonNameMatchesDomainName = checkDomainNameAgainstCertificate(domainNameString, savedSslCertificateIssuedToCNameString);
970 // Format the `issuedToCommonName` color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
971 if (savedSSlCertificateCommonNameMatchesDomainName) {
972 savedSslCertificateIssuedToCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), savedSslCertificateIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
974 savedSslCertificateIssuedToCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), savedSslCertificateIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
977 // Format the start date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
978 if ((savedSslCertificateStartDate != null) && savedSslCertificateStartDate.after(currentDate)) { // The certificate start date is in the future.
979 savedSslCertificateStartDateStringBuilder.setSpan(redColorSpan, startDateLabel.length(), savedSslCertificateStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
980 } else { // The certificate start date is in the past.
981 savedSslCertificateStartDateStringBuilder.setSpan(blueColorSpan, startDateLabel.length(), savedSslCertificateStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
984 // Format the end date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
985 if ((savedSslCertificateEndDate != null) && savedSslCertificateEndDate.before(currentDate)) { // The certificate end date is in the past.
986 savedSslCertificateEndDateStringBuilder.setSpan(redColorSpan, endDateLabel.length(), savedSslCertificateEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
987 } else { // The certificate end date is in the future.
988 savedSslCertificateEndDateStringBuilder.setSpan(blueColorSpan, endDateLabel.length(), savedSslCertificateEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
991 // Display the current website SSL certificate strings.
992 savedSslCertificateIssuedToCNameTextView.setText(savedSslCertificateIssuedToCNameStringBuilder);
993 savedSslCertificateIssuedToONameTextView.setText(savedSslCertificateIssuedToONameStringBuilder);
994 savedSslCertificateIssuedToUNameTextView.setText(savedSslCertificateIssuedToUNameStringBuilder);
995 savedSslCertificateIssuedByCNameTextView.setText(savedSslCertificateIssuedByCNameStringBuilder);
996 savedSslCertificateIssuedByONameTextView.setText(savedSslCertificateIssuedByONameStringBuilder);
997 savedSslCertificateIssuedByUNameTextView.setText(savedSslCertificateIssuedByUNameStringBuilder);
998 savedSslCertificateStartDateTextView.setText(savedSslCertificateStartDateStringBuilder);
999 savedSslCertificateEndDateTextView.setText(savedSslCertificateEndDateStringBuilder);
1001 // Populate the current website SSL certificate if there is one.
1002 if (currentWebsiteSslCertificate != null) {
1003 // Get the strings from the SSL certificate.
1004 String currentWebsiteCertificateIssuedToCNameString = currentWebsiteSslCertificate.getIssuedTo().getCName();
1005 String currentWebsiteCertificateIssuedToONameString = currentWebsiteSslCertificate.getIssuedTo().getOName();
1006 String currentWebsiteCertificateIssuedToUNameString = currentWebsiteSslCertificate.getIssuedTo().getUName();
1007 String currentWebsiteCertificateIssuedByCNameString = currentWebsiteSslCertificate.getIssuedBy().getCName();
1008 String currentWebsiteCertificateIssuedByONameString = currentWebsiteSslCertificate.getIssuedBy().getOName();
1009 String currentWebsiteCertificateIssuedByUNameString = currentWebsiteSslCertificate.getIssuedBy().getUName();
1010 Date currentWebsiteCertificateStartDate = currentWebsiteSslCertificate.getValidNotBeforeDate();
1011 Date currentWebsiteCertificateEndDate = currentWebsiteSslCertificate.getValidNotAfterDate();
1013 // Create a `SpannableStringBuilder` for each `TextView` that needs multiple colors of text.
1014 SpannableStringBuilder currentWebsiteCertificateIssuedToCNameStringBuilder = new SpannableStringBuilder(cNameLabel + currentWebsiteCertificateIssuedToCNameString);
1015 SpannableStringBuilder currentWebsiteCertificateIssuedToONameStringBuilder = new SpannableStringBuilder(oNameLabel + currentWebsiteCertificateIssuedToONameString);
1016 SpannableStringBuilder currentWebsiteCertificateIssuedToUNameStringBuilder = new SpannableStringBuilder(uNameLabel + currentWebsiteCertificateIssuedToUNameString);
1017 SpannableStringBuilder currentWebsiteCertificateIssuedByCNameStringBuilder = new SpannableStringBuilder(cNameLabel + currentWebsiteCertificateIssuedByCNameString);
1018 SpannableStringBuilder currentWebsiteCertificateIssuedByONameStringBuilder = new SpannableStringBuilder(oNameLabel + currentWebsiteCertificateIssuedByONameString);
1019 SpannableStringBuilder currentWebsiteCertificateIssuedByUNameStringBuilder = new SpannableStringBuilder(uNameLabel + currentWebsiteCertificateIssuedByUNameString);
1020 SpannableStringBuilder currentWebsiteCertificateStartDateStringBuilder = new SpannableStringBuilder(startDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG)
1021 .format(currentWebsiteCertificateStartDate));
1022 SpannableStringBuilder currentWebsiteCertificateEndDateStringBuilder = new SpannableStringBuilder(endDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG)
1023 .format(currentWebsiteCertificateEndDate));
1025 // Setup the `StringBuilders` to display the general certificate information in blue. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
1026 currentWebsiteCertificateIssuedToONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), currentWebsiteCertificateIssuedToONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1027 currentWebsiteCertificateIssuedToUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), currentWebsiteCertificateIssuedToUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1028 currentWebsiteCertificateIssuedByCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), currentWebsiteCertificateIssuedByCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1029 currentWebsiteCertificateIssuedByONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), currentWebsiteCertificateIssuedByONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1030 currentWebsiteCertificateIssuedByUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), currentWebsiteCertificateIssuedByUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1032 // Check the certificate `Common Name` against the domain name.
1033 boolean currentWebsiteCertificateCommonNameMatchesDomainName = checkDomainNameAgainstCertificate(domainNameString, currentWebsiteCertificateIssuedToCNameString);
1035 // Format the `issuedToCommonName` color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
1036 if (currentWebsiteCertificateCommonNameMatchesDomainName) {
1037 currentWebsiteCertificateIssuedToCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), currentWebsiteCertificateIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1039 currentWebsiteCertificateIssuedToCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), currentWebsiteCertificateIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1042 // Format the start date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
1043 if (currentWebsiteCertificateStartDate.after(currentDate)) { // The certificate start date is in the future.
1044 currentWebsiteCertificateStartDateStringBuilder.setSpan(redColorSpan, startDateLabel.length(), currentWebsiteCertificateStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1045 } else { // The certificate start date is in the past.
1046 currentWebsiteCertificateStartDateStringBuilder.setSpan(blueColorSpan, startDateLabel.length(), currentWebsiteCertificateStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1049 // Format the end date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
1050 if (currentWebsiteCertificateEndDate.before(currentDate)) { // The certificate end date is in the past.
1051 currentWebsiteCertificateEndDateStringBuilder.setSpan(redColorSpan, endDateLabel.length(), currentWebsiteCertificateEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1052 } else { // The certificate end date is in the future.
1053 currentWebsiteCertificateEndDateStringBuilder.setSpan(blueColorSpan, endDateLabel.length(), currentWebsiteCertificateEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1056 // Display the current website SSL certificate strings.
1057 currentWebsiteCertificateIssuedToCNameTextView.setText(currentWebsiteCertificateIssuedToCNameStringBuilder);
1058 currentWebsiteCertificateIssuedToONameTextView.setText(currentWebsiteCertificateIssuedToONameStringBuilder);
1059 currentWebsiteCertificateIssuedToUNameTextView.setText(currentWebsiteCertificateIssuedToUNameStringBuilder);
1060 currentWebsiteCertificateIssuedByCNameTextView.setText(currentWebsiteCertificateIssuedByCNameStringBuilder);
1061 currentWebsiteCertificateIssuedByONameTextView.setText(currentWebsiteCertificateIssuedByONameStringBuilder);
1062 currentWebsiteCertificateIssuedByUNameTextView.setText(currentWebsiteCertificateIssuedByUNameStringBuilder);
1063 currentWebsiteCertificateStartDateTextView.setText(currentWebsiteCertificateStartDateStringBuilder);
1064 currentWebsiteCertificateEndDateTextView.setText(currentWebsiteCertificateEndDateStringBuilder);
1067 // Set the initial display status for the SSL certificates.
1068 if (pinnedSslCertificateSwitch.isChecked()) {
1069 // Set the visibility of the saved SSL certificate.
1070 if (savedSslCertificateIssuedToCNameString == null) {
1071 savedSslCertificateLinearLayout.setVisibility(View.GONE);
1073 savedSslCertificateLinearLayout.setVisibility(View.VISIBLE);
1076 // Set the visibility of the current website SSL certificate.
1077 if (currentWebsiteSslCertificate == null) {
1078 // Hide the SSL certificate.
1079 currentWebsiteCertificateLinearLayout.setVisibility(View.GONE);
1081 // Show the instruction.
1082 noCurrentWebsiteCertificateTextView.setVisibility(View.VISIBLE);
1084 // Show the SSL certificate.
1085 currentWebsiteCertificateLinearLayout.setVisibility(View.VISIBLE);
1087 // Hide the instruction.
1088 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
1091 // Set the status of the radio buttons.
1092 if (savedSslCertificateLinearLayout.getVisibility() == View.VISIBLE) { // The saved SSL certificate is displayed.
1093 savedSslCertificateRadioButton.setChecked(true);
1094 currentWebsiteCertificateRadioButton.setChecked(false);
1095 } else if (currentWebsiteCertificateLinearLayout.getVisibility() == View.VISIBLE) { // The saved SSL certificate is hidden but the current website SSL certificate is visible.
1096 currentWebsiteCertificateRadioButton.setChecked(true);
1097 savedSslCertificateRadioButton.setChecked(false);
1098 } else { // Neither SSL certificate is visible.
1099 savedSslCertificateRadioButton.setChecked(false);
1100 currentWebsiteCertificateRadioButton.setChecked(false);
1102 } else { // `pinnedSslCertificateSwitch` is not checked.
1103 // Hide the SSl certificates and instructions.
1104 savedSslCertificateLinearLayout.setVisibility(View.GONE);
1105 currentWebsiteCertificateLinearLayout.setVisibility(View.GONE);
1106 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
1108 // Uncheck the radio buttons.
1109 savedSslCertificateRadioButton.setChecked(false);
1110 currentWebsiteCertificateRadioButton.setChecked(false);
1114 // Set the JavaScript switch listener.
1115 javaScriptEnabledSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1116 if (isChecked) { // JavaScript is enabled.
1117 // Update the JavaScript icon.
1118 javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.javascript_enabled));
1120 // Enable the DOM storage `Switch`.
1121 domStorageEnabledSwitch.setEnabled(true);
1123 // Update the DOM storage icon.
1124 if (domStorageEnabledSwitch.isChecked()) { // DOM storage is enabled.
1125 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_enabled));
1126 } else { // DOM storage is disabled.
1127 // Set the icon according to the theme.
1128 if (MainWebViewActivity.darkTheme) {
1129 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_dark));
1131 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_light));
1134 } else { // JavaScript is disabled.
1135 // Update the JavaScript icon.
1136 javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.privacy_mode));
1138 // Disable the DOM storage `Switch`.
1139 domStorageEnabledSwitch.setEnabled(false);
1141 // Set the DOM storage icon according to the theme.
1142 if (MainWebViewActivity.darkTheme) {
1143 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_dark));
1145 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_light));
1150 // Set the first-party cookies switch listener.
1151 firstPartyCookiesEnabledSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1152 if (isChecked) { // First-party cookies are enabled.
1153 // Update the first-party cookies icon.
1154 firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_enabled));
1156 // Enable the third-party cookies switch.
1157 thirdPartyCookiesEnabledSwitch.setEnabled(true);
1159 // Update the third-party cookies icon.
1160 if (thirdPartyCookiesEnabledSwitch.isChecked()) { // Third-party cookies are enabled.
1161 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_warning));
1162 } else { // Third-party cookies are disabled.
1163 // Set the third-party cookies icon according to the theme.
1164 if (MainWebViewActivity.darkTheme) {
1165 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_dark));
1167 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_light));
1170 } else { // First-party cookies are disabled.
1171 // Update the first-party cookies icon according to the theme.
1172 if (MainWebViewActivity.darkTheme) {
1173 firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_dark));
1175 firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_light));
1178 // Disable the third-party cookies switch.
1179 thirdPartyCookiesEnabledSwitch.setEnabled(false);
1181 // Set the third-party cookies icon according to the theme.
1182 if (MainWebViewActivity.darkTheme) {
1183 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_ghosted_dark));
1185 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_ghosted_light));
1190 // Set the third-party cookies switch listener.
1191 thirdPartyCookiesEnabledSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1194 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_warning));
1196 // Update the third-party cookies icon according to the theme.
1197 if (MainWebViewActivity.darkTheme) {
1198 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_dark));
1200 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_light));
1205 // Set the DOM Storage switch listener.
1206 domStorageEnabledSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1209 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_enabled));
1211 // Set the icon according to the theme.
1212 if (MainWebViewActivity.darkTheme) {
1213 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_dark));
1215 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_light));
1220 // Set the form data switch listener. It can be removed once the minimum API >= 26.
1221 if (Build.VERSION.SDK_INT < 26) {
1222 formDataEnabledSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1225 formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_enabled));
1227 // Set the icon according to the theme.
1228 if (MainWebViewActivity.darkTheme) {
1229 formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_disabled_dark));
1231 formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_disabled_light));
1237 // Set the EasyList switch listener.
1238 easyListSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1240 if (isChecked) { // EasyList is on.
1241 // Set the icon according to the theme.
1242 if (MainWebViewActivity.darkTheme) {
1243 easyListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_enabled_dark));
1245 easyListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_enabled_light));
1247 } else { // EasyList is off.
1248 // Set the icon according to the theme.
1249 if (MainWebViewActivity.darkTheme) {
1250 easyListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_disabled_dark));
1252 easyListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_disabled_light));
1257 // Set the EasyPrivacy switch listener.
1258 easyPrivacySwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1260 if (isChecked) { // EasyPrivacy is on.
1261 // Set the icon according to the theme.
1262 if (MainWebViewActivity.darkTheme) {
1263 easyPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_enabled_dark));
1265 easyPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_enabled_light));
1267 } else { // EasyPrivacy is off.
1268 // Set the icon according to the theme.
1269 if (MainWebViewActivity.darkTheme) {
1270 easyPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_disabled_dark));
1272 easyPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_disabled_light));
1277 // Set the Fanboy's Annoyance List switch listener.
1278 fanboysAnnoyanceListSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1279 // Update the icon and Fanboy's Social Blocking List.
1280 if (isChecked) { // Fanboy's Annoyance List is on.
1281 // Set the icon according to the theme.
1282 if (MainWebViewActivity.darkTheme) {
1283 fanboysAnnoyanceListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_dark));
1285 fanboysAnnoyanceListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_light));
1288 // Disable the Fanboy's Social Blocking List switch.
1289 fanboysSocialBlockingListSwitch.setEnabled(false);
1291 // Update the Fanboy's Social Blocking List icon according to the theme.
1292 if (MainWebViewActivity.darkTheme) {
1293 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_ghosted_dark));
1295 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_ghosted_light));
1297 } else { // Fanboy's Annoyance List is off.
1298 // Set the icon according to the theme.
1299 if (MainWebViewActivity.darkTheme) {
1300 fanboysAnnoyanceListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_dark));
1302 fanboysAnnoyanceListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_light));
1305 // Enable the Fanboy's Social Blocking List switch.
1306 fanboysSocialBlockingListSwitch.setEnabled(true);
1308 // Update the Fanboy's Social Blocking List icon.
1309 if (fanboysSocialBlockingListSwitch.isChecked()) { // Fanboy's Social Blocking List is on.
1310 // Update the icon according to the theme.
1311 if (MainWebViewActivity.darkTheme) {
1312 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_dark));
1314 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_light));
1316 } else { // Fanboy's Social Blocking List is off.
1317 // Update the icon according to the theme.
1318 if (MainWebViewActivity.darkTheme) {
1319 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_dark));
1321 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_light));
1328 // Set the Fanboy's Social Blocking List switch listener.
1329 fanboysSocialBlockingListSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1331 if (isChecked) { // Fanboy's Social Blocking List is on.
1332 // Set the icon according to the theme.
1333 if (MainWebViewActivity.darkTheme) {
1334 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_dark));
1336 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_light));
1338 } else { // Fanboy's Social Blocking List is off.
1339 // Set the icon according to the theme.
1340 if (MainWebViewActivity.darkTheme) {
1341 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_dark));
1343 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_light));
1348 // Set the UltraPrivacy switch listener.
1349 ultraPrivacySwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1351 if (isChecked) { // UltraPrivacy is on.
1352 // Set the icon according to the theme.
1353 if (MainWebViewActivity.darkTheme) {
1354 ultraPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_enabled_dark));
1356 ultraPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_enabled_light));
1358 } else { // UltraPrivacy is off.
1359 // Set the icon according to the theme.
1360 if (MainWebViewActivity.darkTheme) {
1361 ultraPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_disabled_dark));
1363 ultraPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_disabled_light));
1368 // Set the block all third-party requests switch listener.
1369 blockAllThirdPartyRequestsSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1371 if (isChecked) { // Blocking all third-party requests is on.
1372 // Set the icon according to the theme.
1373 if (MainWebViewActivity.darkTheme) {
1374 blockAllThirdPartyRequestsImageView.setImageDrawable(resources.getDrawable(R.drawable.block_all_third_party_requests_enabled_dark));
1376 blockAllThirdPartyRequestsImageView.setImageDrawable(resources.getDrawable(R.drawable.block_all_third_party_requests_enabled_light));
1378 } else { // Blocking all third-party requests is off.
1379 // Set the icon according to the theme.
1380 if (MainWebViewActivity.darkTheme) {
1381 blockAllThirdPartyRequestsImageView.setImageDrawable(resources.getDrawable(R.drawable.block_all_third_party_requests_disabled_dark));
1383 blockAllThirdPartyRequestsImageView.setImageDrawable(resources.getDrawable(R.drawable.block_all_third_party_requests_disabled_light));
1388 // Set the user agent spinner listener.
1389 userAgentSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1391 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1392 // Set the new user agent.
1394 case MainWebViewActivity.DOMAINS_SYSTEM_DEFAULT_USER_AGENT:
1395 // Show the user agent TextView.
1396 userAgentTextView.setVisibility(View.VISIBLE);
1398 // Hide the custom user agent EditText.
1399 customUserAgentEditText.setVisibility(View.GONE);
1401 // Set the user text.
1402 switch (defaultUserAgentArrayPosition) {
1403 case MainWebViewActivity.UNRECOGNIZED_USER_AGENT: // The default user agent name is not on the canonical list.
1404 // This is probably because it was set in an older version of Privacy Browser before the switch to persistent user agent names.
1405 userAgentTextView.setText(defaultUserAgentName);
1408 case MainWebViewActivity.SETTINGS_WEBVIEW_DEFAULT_USER_AGENT:
1409 // Display the `WebView` default user agent.
1410 userAgentTextView.setText(webViewDefaultUserAgentString);
1413 case MainWebViewActivity.SETTINGS_CUSTOM_USER_AGENT:
1414 // Display the custom user agent.
1415 userAgentTextView.setText(defaultCustomUserAgentString);
1419 // Get the user agent string from the user agent data array.
1420 userAgentTextView.setText(userAgentDataArray[defaultUserAgentArrayPosition]);
1424 case MainWebViewActivity.DOMAINS_WEBVIEW_DEFAULT_USER_AGENT:
1425 // Show the user agent TextView and set the text.
1426 userAgentTextView.setVisibility(View.VISIBLE);
1427 userAgentTextView.setText(webViewDefaultUserAgentString);
1429 // Hide the custom user agent EditTex.
1430 customUserAgentEditText.setVisibility(View.GONE);
1433 case MainWebViewActivity.DOMAINS_CUSTOM_USER_AGENT:
1434 // Hide the user agent TextView.
1435 userAgentTextView.setVisibility(View.GONE);
1437 // Show the custom user agent EditText and set the current user agent name as the text.
1438 customUserAgentEditText.setVisibility(View.VISIBLE);
1439 customUserAgentEditText.setText(currentUserAgentName);
1443 // 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.
1444 userAgentTextView.setVisibility(View.VISIBLE);
1445 userAgentTextView.setText(userAgentDataArray[position - 1]);
1447 // Hide `customUserAgentEditText`.
1448 customUserAgentEditText.setVisibility(View.GONE);
1453 public void onNothingSelected(AdapterView<?> parent) {
1458 // Set the font size spinner listener.
1459 fontSizeSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1461 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1462 // Update the display options for `fontSizeTextView`.
1463 if (position == 0) { // System default font size has been selected. Display `fontSizeTextView`.
1464 fontSizeTextView.setVisibility(View.VISIBLE);
1465 } else { // A custom font size has been selected. Hide `fontSizeTextView`.
1466 fontSizeTextView.setVisibility(View.GONE);
1471 public void onNothingSelected(AdapterView<?> parent) {
1476 // Set the swipe to refresh spinner listener.
1477 swipeToRefreshSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1479 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1480 // 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.
1482 case DomainsDatabaseHelper.SWIPE_TO_REFRESH_SYSTEM_DEFAULT:
1483 if (defaultSwipeToRefresh) { // Swipe to refresh enabled by default.
1484 // Set the icon according to the theme.
1485 if (MainWebViewActivity.darkTheme) {
1486 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_enabled_dark));
1488 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_enabled_light));
1490 } else { // Swipe to refresh disabled by default.
1491 // Set the icon according to the theme.
1492 if (MainWebViewActivity.darkTheme) {
1493 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_disabled_dark));
1495 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_disabled_light));
1499 // Show the swipe to refresh TextView.
1500 swipeToRefreshTextView.setVisibility(View.VISIBLE);
1503 case DomainsDatabaseHelper.SWIPE_TO_REFRESH_ENABLED:
1504 // Set the icon according to the theme.
1505 if (MainWebViewActivity.darkTheme) {
1506 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_enabled_dark));
1508 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_enabled_light));
1511 // Hide the swipe to refresh TextView.
1512 swipeToRefreshTextView.setVisibility(View.GONE);
1515 case DomainsDatabaseHelper.SWIPE_TO_REFRESH_DISABLED:
1516 // Set the icon according to the theme.
1517 if (MainWebViewActivity.darkTheme) {
1518 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_disabled_dark));
1520 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_disabled_light));
1523 // Hide the swipe to refresh TextView.
1524 swipeToRefreshTextView.setVisibility(View.GONE);
1529 public void onNothingSelected(AdapterView<?> parent) {
1534 // Set the night mode spinner listener.
1535 nightModeSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1537 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1538 // 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.
1540 case DomainsDatabaseHelper.NIGHT_MODE_SYSTEM_DEFAULT:
1541 if (defaultNightMode) { // Night mode enabled by default.
1542 // Set the icon according to the theme.
1543 if (MainWebViewActivity.darkTheme) {
1544 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_dark));
1546 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_light));
1548 } else { // Night mode disabled by default.
1549 // Set the icon according to the theme.
1550 if (MainWebViewActivity.darkTheme) {
1551 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_dark));
1553 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_light));
1557 // Show the night mode TextView.
1558 nightModeTextView.setVisibility(View.VISIBLE);
1561 case DomainsDatabaseHelper.NIGHT_MODE_ENABLED:
1562 // Set the icon according to the theme.
1563 if (MainWebViewActivity.darkTheme) {
1564 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_dark));
1566 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_light));
1569 // Hide `nightModeTextView`.
1570 nightModeTextView.setVisibility(View.GONE);
1573 case DomainsDatabaseHelper.NIGHT_MODE_DISABLED:
1574 // Set the icon according to the theme.
1575 if (MainWebViewActivity.darkTheme) {
1576 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_dark));
1578 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_light));
1581 // Hide `nightModeTextView`.
1582 nightModeTextView.setVisibility(View.GONE);
1586 // Create a `boolean` to store the current night mode setting.
1587 boolean currentNightModeEnabled = (position == DomainsDatabaseHelper.NIGHT_MODE_ENABLED) || ((position == DomainsDatabaseHelper.NIGHT_MODE_SYSTEM_DEFAULT) && defaultNightMode);
1589 // Disable the JavaScript `Switch` if night mode is enabled.
1590 if (currentNightModeEnabled) {
1591 javaScriptEnabledSwitch.setEnabled(false);
1593 javaScriptEnabledSwitch.setEnabled(true);
1596 // Update the JavaScript icon.
1597 if ((javaScriptEnabledInt == 1) || currentNightModeEnabled) {
1598 javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.javascript_enabled));
1600 javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.privacy_mode));
1603 // Update the DOM storage status.
1604 if ((javaScriptEnabledInt == 1) || currentNightModeEnabled) { // JavaScript is enabled.
1605 // Enable the DOM storage `Switch`.
1606 domStorageEnabledSwitch.setEnabled(true);
1608 // Set the DOM storage status. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
1609 if (domStorageEnabledInt == 1) { // Both JavaScript and DOM storage are enabled.
1610 domStorageEnabledSwitch.setChecked(true);
1611 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_enabled));
1612 } else { // JavaScript is enabled but DOM storage is disabled.
1613 // Set the DOM storage switch to off.
1614 domStorageEnabledSwitch.setChecked(false);
1616 // Set the icon according to the theme.
1617 if (MainWebViewActivity.darkTheme) {
1618 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_dark));
1620 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_light));
1623 } else { // JavaScript is disabled.
1624 // Disable the DOM storage `Switch`.
1625 domStorageEnabledSwitch.setEnabled(false);
1627 // Set the checked status of DOM storage.
1628 if (domStorageEnabledInt == 1) { // DOM storage is enabled but JavaScript is disabled.
1629 domStorageEnabledSwitch.setChecked(true);
1630 } else { // Both JavaScript and DOM storage are disabled.
1631 domStorageEnabledSwitch.setChecked(false);
1634 // Set the icon according to the theme.
1635 if (MainWebViewActivity.darkTheme) {
1636 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_dark));
1638 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_light));
1644 public void onNothingSelected(AdapterView<?> parent) {
1649 // Set the display webpage images spinner listener.
1650 displayWebpageImagesSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1652 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1653 // Update the icon and the visibility of `displayImagesTextView`.
1655 case DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_SYSTEM_DEFAULT:
1656 if (defaultDisplayWebpageImages) {
1657 // Set the icon according to the theme.
1658 if (MainWebViewActivity.darkTheme) {
1659 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_dark));
1661 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_light));
1664 // Set the icon according to the theme.
1665 if (MainWebViewActivity.darkTheme) {
1666 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_dark));
1668 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_light));
1672 // Show `displayImagesTextView`.
1673 displayImagesTextView.setVisibility(View.VISIBLE);
1676 case DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_ENABLED:
1677 // Set the icon according to the theme.
1678 if (MainWebViewActivity.darkTheme) {
1679 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_dark));
1681 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_light));
1684 // Hide `displayImagesTextView`.
1685 displayImagesTextView.setVisibility(View.GONE);
1688 case DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_DISABLED:
1689 // Set the icon according to the theme.
1690 if (MainWebViewActivity.darkTheme) {
1691 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_dark));
1693 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_light));
1696 // Hide `displayImagesTextView`.
1697 displayImagesTextView.setVisibility(View.GONE);
1703 public void onNothingSelected(AdapterView<?> parent) {
1708 // Set the pinned SSL certificate switch listener.
1709 pinnedSslCertificateSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1711 if (isChecked) { // Pinned SSL certificate is enabled.
1712 // Set the icon according to the theme.
1713 if (MainWebViewActivity.darkTheme) {
1714 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_dark));
1716 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_light));
1719 // Update the visibility of the saved SSL certificate.
1720 if (savedSslCertificateIssuedToCNameString == null) {
1721 savedSslCertificateLinearLayout.setVisibility(View.GONE);
1723 savedSslCertificateLinearLayout.setVisibility(View.VISIBLE);
1726 // Update the visibility of the current website SSL certificate.
1727 if (currentWebsiteSslCertificate == null) {
1728 // Hide the SSL certificate.
1729 currentWebsiteCertificateLinearLayout.setVisibility(View.GONE);
1731 // Show the instruction.
1732 noCurrentWebsiteCertificateTextView.setVisibility(View.VISIBLE);
1734 // Show the SSL certificate.
1735 currentWebsiteCertificateLinearLayout.setVisibility(View.VISIBLE);
1737 // Hide the instruction.
1738 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
1741 // Set the status of the radio buttons.
1742 if (savedSslCertificateLinearLayout.getVisibility() == View.VISIBLE) { // The saved SSL certificate is displayed.
1743 savedSslCertificateRadioButton.setChecked(true);
1744 currentWebsiteCertificateRadioButton.setChecked(false);
1745 } else if (currentWebsiteCertificateLinearLayout.getVisibility() == View.VISIBLE) { // The saved SSL certificate is hidden but the current website SSL certificate is visible.
1746 currentWebsiteCertificateRadioButton.setChecked(true);
1747 savedSslCertificateRadioButton.setChecked(false);
1748 } else { // Neither SSL certificate is visible.
1749 savedSslCertificateRadioButton.setChecked(false);
1750 currentWebsiteCertificateRadioButton.setChecked(false);
1752 } else { // Pinned SSL certificate is disabled.
1753 // Set the icon according to the theme.
1754 if (MainWebViewActivity.darkTheme) {
1755 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_dark));
1757 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_light));
1760 // Hide the SSl certificates and instructions.
1761 savedSslCertificateLinearLayout.setVisibility(View.GONE);
1762 currentWebsiteCertificateLinearLayout.setVisibility(View.GONE);
1763 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
1765 // Uncheck the radio buttons.
1766 savedSslCertificateRadioButton.setChecked(false);
1767 currentWebsiteCertificateRadioButton.setChecked(false);
1771 savedSslCertificateLinearLayout.setOnClickListener((View v) -> {
1772 savedSslCertificateRadioButton.setChecked(true);
1773 currentWebsiteCertificateRadioButton.setChecked(false);
1776 savedSslCertificateRadioButton.setOnClickListener((View v) -> {
1777 savedSslCertificateRadioButton.setChecked(true);
1778 currentWebsiteCertificateRadioButton.setChecked(false);
1781 currentWebsiteCertificateLinearLayout.setOnClickListener((View v) -> {
1782 currentWebsiteCertificateRadioButton.setChecked(true);
1783 savedSslCertificateRadioButton.setChecked(false);
1786 currentWebsiteCertificateRadioButton.setOnClickListener((View v) -> {
1787 currentWebsiteCertificateRadioButton.setChecked(true);
1788 savedSslCertificateRadioButton.setChecked(false);
1791 return domainSettingsView;
1794 private boolean checkDomainNameAgainstCertificate(String domainName, String certificateCommonName) {
1795 // Initialize `domainNamesMatch`.
1796 boolean domainNamesMatch = false;
1798 // Check various wildcard permutations if `domainName` and `certificateCommonName` are not empty.
1799 // `noinspection ConstantCondition` removes Android Studio's incorrect lint warning that `domainName` can never be `null`.
1800 //noinspection ConstantConditions
1801 if ((domainName != null) && (certificateCommonName != null)) {
1802 // Check if the domains match.
1803 if (domainName.equals(certificateCommonName)) {
1804 domainNamesMatch = true;
1807 // If `domainName` starts with a wildcard, check the base domain against all the subdomains of `certificateCommonName`.
1808 if (!domainNamesMatch && domainName.startsWith("*.") && (domainName.length() > 2)) {
1809 // Remove the initial `*.`.
1810 String baseDomainName = domainName.substring(2);
1812 // Setup a copy of `certificateCommonName` to test subdomains.
1813 String certificateCommonNameSubdomain = certificateCommonName;
1815 // Check all the subdomains in `certificateCommonNameSubdomain` against `baseDomainName`.
1816 while (!domainNamesMatch && certificateCommonNameSubdomain.contains(".")) { // Stop checking if we know that `domainNamesMatch` is `true` or if we run out of `.`.
1817 // Test the `certificateCommonNameSubdomain` against `baseDomainName`.
1818 if (certificateCommonNameSubdomain.equals(baseDomainName)) {
1819 domainNamesMatch = true;
1822 // Strip out the lowest subdomain of `certificateCommonNameSubdomain`.
1824 certificateCommonNameSubdomain = certificateCommonNameSubdomain.substring(certificateCommonNameSubdomain.indexOf(".") + 1);
1825 } catch (IndexOutOfBoundsException e) { // `certificateCommonNameSubdomain` ends with `.`.
1826 certificateCommonNameSubdomain = "";
1831 // If `certificateCommonName` starts with a wildcard, check the base common name against all the subdomains of `domainName`.
1832 if (!domainNamesMatch && certificateCommonName.startsWith("*.") && (certificateCommonName.length() > 2)) {
1833 // Remove the initial `*.`.
1834 String baseCertificateCommonName = certificateCommonName.substring(2);
1836 // Setup a copy of `domainName` to test subdomains.
1837 String domainNameSubdomain = domainName;
1839 // Check all the subdomains in `domainNameSubdomain` against `baseCertificateCommonName`.
1840 while (!domainNamesMatch && domainNameSubdomain.contains(".") && (domainNameSubdomain.length() > 2)) {
1841 // Test the `domainNameSubdomain` against `baseCertificateCommonName`.
1842 if (domainNameSubdomain.equals(baseCertificateCommonName)) {
1843 domainNamesMatch = true;
1846 // Strip out the lowest subdomain of `domainNameSubdomain`.
1848 domainNameSubdomain = domainNameSubdomain.substring(domainNameSubdomain.indexOf(".") + 1);
1849 } catch (IndexOutOfBoundsException e) { // `domainNameSubdomain` ends with `.`.
1850 domainNameSubdomain = "";
1855 // If both names start with a wildcard, check if the root of one contains the root of the other.
1856 if (!domainNamesMatch && domainName.startsWith("*.") && (domainName.length() > 2) && certificateCommonName.startsWith("*.") && (certificateCommonName.length() > 2)) {
1857 // Remove the wildcards.
1858 String rootDomainName = domainName.substring(2);
1859 String rootCertificateCommonName = certificateCommonName.substring(2);
1861 // Check if one name ends with the contents of the other. If so, there will be overlap in the their wildcard subdomains.
1862 if (rootDomainName.endsWith(rootCertificateCommonName) || rootCertificateCommonName.endsWith(rootDomainName)) {
1863 domainNamesMatch = true;
1868 return domainNamesMatch;