2 * Copyright © 2017-2018 Soren Stoutner <soren@stoutner.com>.
4 * This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
6 * Privacy Browser is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * Privacy Browser is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with Privacy Browser. If not, see <http://www.gnu.org/licenses/>.
20 package com.stoutner.privacybrowser.fragments;
22 import android.annotation.SuppressLint;
23 import android.content.Context;
24 import android.content.SharedPreferences;
25 import android.content.res.Resources;
26 import android.database.Cursor;
27 import android.net.http.SslCertificate;
28 import android.os.Build;
29 import android.os.Bundle;
30 // We have to use `android.support.v4.app.Fragment` until minimum API >= 23. Otherwise we cannot call `getContext()`.
31 import android.preference.PreferenceManager;
32 import android.support.annotation.NonNull;
33 import android.support.v4.app.Fragment;
34 import android.text.Editable;
35 import android.text.SpannableStringBuilder;
36 import android.text.Spanned;
37 import android.text.TextWatcher;
38 import android.text.style.ForegroundColorSpan;
39 import android.view.LayoutInflater;
40 import android.view.View;
41 import android.view.ViewGroup;
42 import android.webkit.WebView;
43 import android.widget.AdapterView;
44 import android.widget.ArrayAdapter;
45 import android.widget.CompoundButton;
46 import android.widget.EditText;
47 import android.widget.ImageView;
48 import android.widget.LinearLayout;
49 import android.widget.RadioButton;
50 import android.widget.Spinner;
51 import android.widget.Switch;
52 import android.widget.TextView;
54 import com.stoutner.privacybrowser.R;
55 import com.stoutner.privacybrowser.activities.MainWebViewActivity;
56 import com.stoutner.privacybrowser.helpers.DomainsDatabaseHelper;
58 import java.text.DateFormat;
59 import java.util.Calendar;
60 import java.util.Date;
62 public class DomainSettingsFragment extends Fragment {
63 // `DATABASE_ID` is used by activities calling this fragment.
64 public static final String DATABASE_ID = "database_id";
66 // `databaseId` is public static so it can be accessed from `DomainsActivity`. It is also used in `onCreate()` and `onCreateView()`.
67 public static int databaseId;
70 public void onCreate(Bundle savedInstanceState) {
71 super.onCreate(savedInstanceState);
73 // Remove the lint warning that `getArguments` might be null.
74 assert getArguments() != null;
76 // Store the database id in `databaseId`.
77 databaseId = getArguments().getInt(DATABASE_ID);
80 // We have to use the deprecated `getDrawable()` 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 defaultUserAgentString = sharedPreferences.getString("user_agent", "PrivacyBrowser/1.0");
96 final String defaultCustomUserAgentString = sharedPreferences.getString("custom_user_agent", "PrivacyBrowser/1.0");
97 String defaultFontSizeString = sharedPreferences.getString("default_font_size", "100");
98 final boolean defaultDisplayWebpageImagesBoolean = sharedPreferences.getBoolean("display_website_images", true);
99 final boolean defaultNightModeBoolean = sharedPreferences.getBoolean("night_mode", false);
101 // Get handles for the views in the fragment.
102 final EditText domainNameEditText = domainSettingsView.findViewById(R.id.domain_settings_name_edittext);
103 final Switch javaScriptEnabledSwitch = domainSettingsView.findViewById(R.id.domain_settings_javascript_switch);
104 final ImageView javaScriptImageView = domainSettingsView.findViewById(R.id.domain_settings_javascript_imageview);
105 Switch firstPartyCookiesEnabledSwitch = domainSettingsView.findViewById(R.id.domain_settings_first_party_cookies_switch);
106 final ImageView firstPartyCookiesImageView = domainSettingsView.findViewById(R.id.domain_settings_first_party_cookies_imageview);
107 LinearLayout thirdPartyCookiesLinearLayout = domainSettingsView.findViewById(R.id.domain_settings_third_party_cookies_linearlayout);
108 final Switch thirdPartyCookiesEnabledSwitch = domainSettingsView.findViewById(R.id.domain_settings_third_party_cookies_switch);
109 final ImageView thirdPartyCookiesImageView = domainSettingsView.findViewById(R.id.domain_settings_third_party_cookies_imageview);
110 final Switch domStorageEnabledSwitch = domainSettingsView.findViewById(R.id.domain_settings_dom_storage_switch);
111 final ImageView domStorageImageView = domainSettingsView.findViewById(R.id.domain_settings_dom_storage_imageview);
112 Switch formDataEnabledSwitch = domainSettingsView.findViewById(R.id.domain_settings_form_data_switch);
113 final ImageView formDataImageView = domainSettingsView.findViewById(R.id.domain_settings_form_data_imageview);
114 final Spinner userAgentSpinner = domainSettingsView.findViewById(R.id.domain_settings_user_agent_spinner);
115 final TextView userAgentTextView = domainSettingsView.findViewById(R.id.domain_settings_user_agent_textview);
116 final EditText customUserAgentEditText = domainSettingsView.findViewById(R.id.domain_settings_custom_user_agent_edittext);
117 final Spinner fontSizeSpinner = domainSettingsView.findViewById(R.id.domain_settings_font_size_spinner);
118 final TextView fontSizeTextView = domainSettingsView.findViewById(R.id.domain_settings_font_size_textview);
119 final ImageView displayWebpageImagesImageView = domainSettingsView.findViewById(R.id.domain_settings_display_webpage_images_imageview);
120 final Spinner displayWebpageImagesSpinner = domainSettingsView.findViewById(R.id.domain_settings_display_webpage_images_spinner);
121 final TextView displayImagesTextView = domainSettingsView.findViewById(R.id.domain_settings_display_webpage_images_textview);
122 final ImageView nightModeImageView = domainSettingsView.findViewById(R.id.domain_settings_night_mode_imageview);
123 final Spinner nightModeSpinner = domainSettingsView.findViewById(R.id.domain_settings_night_mode_spinner);
124 final TextView nightModeTextView = domainSettingsView.findViewById(R.id.domain_settings_night_mode_textview);
125 final ImageView pinnedSslCertificateImageView = domainSettingsView.findViewById(R.id.domain_settings_pinned_ssl_certificate_imageview);
126 Switch pinnedSslCertificateSwitch = domainSettingsView.findViewById(R.id.domain_settings_pinned_ssl_certificate_switch);
127 final LinearLayout savedSslCertificateLinearLayout = domainSettingsView.findViewById(R.id.saved_ssl_certificate_linearlayout);
128 final RadioButton savedSslCertificateRadioButton = domainSettingsView.findViewById(R.id.saved_ssl_certificate_radiobutton);
129 final TextView savedSslCertificateIssuedToCNameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_to_cname);
130 TextView savedSslCertificateIssuedToONameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_to_oname);
131 TextView savedSslCertificateIssuedToUNameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_to_uname);
132 TextView savedSslCertificateIssuedByCNameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_by_cname);
133 TextView savedSslCertificateIssuedByONameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_by_oname);
134 TextView savedSslCertificateIssuedByUNameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_by_uname);
135 TextView savedSslCertificateStartDateTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_start_date);
136 TextView savedSslCertificateEndDateTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_end_date);
137 final LinearLayout currentWebsiteCertificateLinearLayout = domainSettingsView.findViewById(R.id.current_website_certificate_linearlayout);
138 final RadioButton currentWebsiteCertificateRadioButton = domainSettingsView.findViewById(R.id.current_website_certificate_radiobutton);
139 final TextView currentWebsiteCertificateIssuedToCNameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_to_cname);
140 TextView currentWebsiteCertificateIssuedToONameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_to_oname);
141 TextView currentWebsiteCertificateIssuedToUNameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_to_uname);
142 TextView currentWebsiteCertificateIssuedByCNameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_by_cname);
143 TextView currentWebsiteCertificateIssuedByONameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_by_oname);
144 TextView currentWebsiteCertificateIssuedByUNameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_by_uname);
145 TextView currentWebsiteCertificateStartDateTextView = domainSettingsView.findViewById(R.id.current_website_certificate_start_date);
146 TextView currentWebsiteCertificateEndDateTextView = domainSettingsView.findViewById(R.id.current_website_certificate_end_date);
147 final TextView noCurrentWebsiteCertificateTextView = domainSettingsView.findViewById(R.id.no_current_website_certificate);
149 // Setup the SSL certificate labels.
150 final String cNameLabel = getString(R.string.common_name) + " ";
151 String oNameLabel = getString(R.string.organization) + " ";
152 String uNameLabel = getString(R.string.organizational_unit) + " ";
153 String startDateLabel = getString(R.string.start_date) + " ";
154 String endDateLabel = getString(R.string.end_date) + " ";
156 // Get the current website SSL certificate
157 final SslCertificate currentWebsiteSslCertificate = MainWebViewActivity.sslCertificate;
159 // Initialize the database handler. The two `nulls` do not specify the database name or a `CursorFactory`. The `0` specifies the database version, but that is ignored and set instead using a constant in `DomainsDatabaseHelper`.
160 DomainsDatabaseHelper domainsDatabaseHelper = new DomainsDatabaseHelper(context, null, null, 0);
162 // Get the database `Cursor` for this ID and move it to the first row.
163 Cursor domainCursor = domainsDatabaseHelper.getCursorForId(databaseId);
164 domainCursor.moveToFirst();
166 // Save the `Cursor` entries as variables.
167 String domainNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.DOMAIN_NAME));
168 final int javaScriptEnabledInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_JAVASCRIPT));
169 int firstPartyCookiesEnabledInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FIRST_PARTY_COOKIES));
170 int thirdPartyCookiesEnabledInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_THIRD_PARTY_COOKIES));
171 final int domStorageEnabledInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_DOM_STORAGE));
172 int formDataEnabledInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FORM_DATA));
173 final String currentUserAgentString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.USER_AGENT));
174 int fontSizeInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.FONT_SIZE));
175 int displayImagesInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.DISPLAY_IMAGES));
176 int nightModeInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.NIGHT_MODE));
177 int pinnedSslCertificateInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.PINNED_SSL_CERTIFICATE));
178 final String savedSslCertificateIssuedToCNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_TO_COMMON_NAME));
179 String savedSslCertificateIssuedToONameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_TO_ORGANIZATION));
180 String savedSslCertificateIssuedToUNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_TO_ORGANIZATIONAL_UNIT));
181 String savedSslCertificateIssuedByCNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_BY_COMMON_NAME));
182 String savedSslCertificateIssuedByONameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_BY_ORGANIZATION));
183 String savedSslCertificateIssuedByUNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_BY_ORGANIZATIONAL_UNIT));
185 // Initialize the saved SSL certificate date variables.
186 Date savedSslCertificateStartDate = null;
187 Date savedSslCertificateEndDate = null;
189 // Only get the saved SSL certificate dates from the cursor if they are not set to `0`.
190 if (domainCursor.getLong(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_START_DATE)) != 0) {
191 savedSslCertificateStartDate = new Date(domainCursor.getLong(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_START_DATE)));
194 if (domainCursor.getLong(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_END_DATE)) != 0) {
195 savedSslCertificateEndDate = new Date(domainCursor.getLong(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_END_DATE)));
198 // Create `ArrayAdapters` for the `Spinners`and their `entry values`.
199 ArrayAdapter<CharSequence> userAgentArrayAdapter = ArrayAdapter.createFromResource(context, R.array.domain_settings_user_agent_entries, R.layout.domain_settings_spinner_item);
200 final ArrayAdapter<CharSequence> userAgentEntryValuesArrayAdapter = ArrayAdapter.createFromResource(context, R.array.domain_settings_user_agent_entry_values, R.layout.domain_settings_spinner_item);
201 ArrayAdapter<CharSequence> fontSizeArrayAdapter = ArrayAdapter.createFromResource(context, R.array.domain_settings_font_size_entries, R.layout.domain_settings_spinner_item);
202 ArrayAdapter<CharSequence> fontSizeEntryValuesArrayAdapter = ArrayAdapter.createFromResource(context, R.array.domain_settings_font_size_entry_values, R.layout.domain_settings_spinner_item);
203 final ArrayAdapter<CharSequence> displayImagesArrayAdapter = ArrayAdapter.createFromResource(context, R.array.display_webpage_images_array, R.layout.domain_settings_spinner_item);
204 ArrayAdapter<CharSequence> nightModeArrayAdapter = ArrayAdapter.createFromResource(context, R.array.night_mode_array, R.layout.domain_settings_spinner_item);
206 // Set the `DropDownViewResource` on the `Spinners`.
207 userAgentArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_item);
208 fontSizeArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_item);
209 displayImagesArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_item);
210 nightModeArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_item);
212 // Set the `ArrayAdapters` for the `Spinners`.
213 userAgentSpinner.setAdapter(userAgentArrayAdapter);
214 fontSizeSpinner.setAdapter(fontSizeArrayAdapter);
215 displayWebpageImagesSpinner.setAdapter(displayImagesArrayAdapter);
216 nightModeSpinner.setAdapter(nightModeArrayAdapter);
218 // Create a `SpannableStringBuilder` for each `TextView` that needs multiple colors of text.
219 SpannableStringBuilder savedSslCertificateIssuedToCNameStringBuilder = new SpannableStringBuilder(cNameLabel + savedSslCertificateIssuedToCNameString);
220 SpannableStringBuilder savedSslCertificateIssuedToONameStringBuilder = new SpannableStringBuilder(oNameLabel + savedSslCertificateIssuedToONameString);
221 SpannableStringBuilder savedSslCertificateIssuedToUNameStringBuilder = new SpannableStringBuilder(uNameLabel + savedSslCertificateIssuedToUNameString);
222 SpannableStringBuilder savedSslCertificateIssuedByCNameStringBuilder = new SpannableStringBuilder(cNameLabel + savedSslCertificateIssuedByCNameString);
223 SpannableStringBuilder savedSslCertificateIssuedByONameStringBuilder = new SpannableStringBuilder(oNameLabel + savedSslCertificateIssuedByONameString);
224 SpannableStringBuilder savedSslCertificateIssuedByUNameStringBuilder = new SpannableStringBuilder(uNameLabel + savedSslCertificateIssuedByUNameString);
226 // Initialize the `SpannableStringBuilders` for the SSL certificate dates.
227 SpannableStringBuilder savedSslCertificateStartDateStringBuilder;
228 SpannableStringBuilder savedSslCertificateEndDateStringBuilder;
230 // Leave the SSL certificate dates empty if they are `null`.
231 if (savedSslCertificateStartDate == null) {
232 savedSslCertificateStartDateStringBuilder = new SpannableStringBuilder(startDateLabel);
234 savedSslCertificateStartDateStringBuilder = new SpannableStringBuilder(startDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(savedSslCertificateStartDate));
237 if (savedSslCertificateEndDate == null) {
238 savedSslCertificateEndDateStringBuilder = new SpannableStringBuilder(endDateLabel);
240 savedSslCertificateEndDateStringBuilder = new SpannableStringBuilder(endDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(savedSslCertificateEndDate));
243 // Create a red `ForegroundColorSpan`. We have to use the deprecated `getColor` until API >= 23.
244 final ForegroundColorSpan redColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.red_a700));
246 // Create a blue `ForegroundColorSpan`.
247 final ForegroundColorSpan blueColorSpan;
249 // Set `blueColorSpan` according to the theme. We have to use the deprecated `getColor()` until API >= 23.
250 if (MainWebViewActivity.darkTheme) {
251 //noinspection deprecation
252 blueColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.blue_400));
254 //noinspection deprecation
255 blueColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.blue_700));
258 // Set the domain name from the the database cursor.
259 domainNameEditText.setText(domainNameString);
261 // Update the certificates' `Common Name` color when the domain name text changes.
262 domainNameEditText.addTextChangedListener(new TextWatcher() {
264 public void beforeTextChanged(CharSequence s, int start, int count, int after) {
269 public void onTextChanged(CharSequence s, int start, int before, int count) {
274 public void afterTextChanged(Editable s) {
275 // Get the new domain name.
276 String newDomainName = domainNameEditText.getText().toString();
278 // Check the saved SSL certificate against the new domain name.
279 boolean savedSslCertificateMatchesNewDomainName = checkDomainNameAgainstCertificate(newDomainName, savedSslCertificateIssuedToCNameString);
281 // Create a `SpannableStringBuilder` for the saved certificate `Common Name`.
282 SpannableStringBuilder savedSslCertificateCommonNameStringBuilder = new SpannableStringBuilder(cNameLabel + savedSslCertificateIssuedToCNameString);
284 // Format the saved certificate `Common Name` color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
285 if (savedSslCertificateMatchesNewDomainName) {
286 savedSslCertificateCommonNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), savedSslCertificateCommonNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
288 savedSslCertificateCommonNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), savedSslCertificateCommonNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
291 // Update `savedSslCertificateIssuedToCNameTextView`.
292 savedSslCertificateIssuedToCNameTextView.setText(savedSslCertificateCommonNameStringBuilder);
294 // Update the current website certificate if it exists.
295 if (currentWebsiteSslCertificate != null) {
296 // Get the current website certificate `Common Name`.
297 String currentWebsiteCertificateCommonName = currentWebsiteSslCertificate.getIssuedTo().getCName();
299 // Check the current website certificate against the new domain name.
300 boolean currentWebsiteCertificateMatchesNewDomainName = checkDomainNameAgainstCertificate(newDomainName, currentWebsiteCertificateCommonName);
302 // Create a `SpannableStringBuilder` for the current website certificate `Common Name`.
303 SpannableStringBuilder currentWebsiteCertificateCommonNameStringBuilder = new SpannableStringBuilder(cNameLabel + currentWebsiteCertificateCommonName);
305 // Format the current certificate `Common Name` color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
306 if (currentWebsiteCertificateMatchesNewDomainName) {
307 currentWebsiteCertificateCommonNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), currentWebsiteCertificateCommonNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
309 currentWebsiteCertificateCommonNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), currentWebsiteCertificateCommonNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
312 // Update `currentWebsiteCertificateIssuedToCNameTextView`.
313 currentWebsiteCertificateIssuedToCNameTextView.setText(currentWebsiteCertificateCommonNameStringBuilder);
318 // Create a `boolean` to track if night mode is enabled.
319 boolean nightModeEnabled = (nightModeInt == DomainsDatabaseHelper.NIGHT_MODE_ENABLED) || ((nightModeInt == DomainsDatabaseHelper.NIGHT_MODE_SYSTEM_DEFAULT) && defaultNightModeBoolean);
321 // Disable the JavaScript `Switch` if night mode is enabled.
322 if (nightModeEnabled) {
323 javaScriptEnabledSwitch.setEnabled(false);
325 javaScriptEnabledSwitch.setEnabled(true);
328 // Set the JavaScript icon.
329 if ((javaScriptEnabledInt == 1) || nightModeEnabled) {
330 javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.javascript_enabled));
332 javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.privacy_mode));
335 // Set the JavaScript `Switch` status.
336 if (javaScriptEnabledInt == 1) { // JavaScript is enabled.
337 javaScriptEnabledSwitch.setChecked(true);
338 } else { // JavaScript is disabled.
339 javaScriptEnabledSwitch.setChecked(false);
342 // Set the first-party cookies status. Once minimum API >= 21 we can use a selector as the tint mode instead of specifying different icons.
343 if (firstPartyCookiesEnabledInt == 1) { // First-party cookies are enabled.
344 firstPartyCookiesEnabledSwitch.setChecked(true);
345 firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_enabled));
346 } else { // First-party cookies are disabled.
347 firstPartyCookiesEnabledSwitch.setChecked(false);
349 // Set the icon according to the theme.
350 if (MainWebViewActivity.darkTheme) {
351 firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_dark));
353 firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_light));
357 // Only display third-party cookies if SDK_INT >= 21.
358 if (Build.VERSION.SDK_INT >= 21) { // Third-party cookies can be configured for API >= 21.
359 // Only enable third-party-cookies if first-party cookies are enabled.
360 if (firstPartyCookiesEnabledInt == 1) { // First-party cookies are enabled.
361 // Set the third-party cookies status. Once minimum API >= 21 we can use a selector as the tint mode instead of specifying different icons.
362 if (thirdPartyCookiesEnabledInt == 1) { // Both first-party and third-party cookies are enabled.
363 thirdPartyCookiesEnabledSwitch.setChecked(true);
364 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_warning));
365 } else { // First party cookies are enabled but third-party cookies are disabled.
366 thirdPartyCookiesEnabledSwitch.setChecked(false);
368 // Set the icon according to the theme.
369 if (MainWebViewActivity.darkTheme) {
370 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_dark));
372 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_light));
375 } else { // First-party cookies are disabled.
376 // Set the status of third-party cookies.
377 if (thirdPartyCookiesEnabledInt == 1) {
378 thirdPartyCookiesEnabledSwitch.setChecked(true);
380 thirdPartyCookiesEnabledSwitch.setChecked(false);
383 // Disable the third-party cookies switch.
384 thirdPartyCookiesEnabledSwitch.setEnabled(false);
386 // Set the icon according to the theme.
387 if (MainWebViewActivity.darkTheme) {
388 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_ghosted_dark));
390 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_ghosted_light));
393 } else { // Third-party cookies cannot be configured for API <= 21.
394 // Hide the `LinearLayout` for third-party cookies.
395 thirdPartyCookiesLinearLayout.setVisibility(View.GONE);
398 // Only enable DOM storage if JavaScript is enabled.
399 if ((javaScriptEnabledInt == 1) || nightModeEnabled) { // JavaScript is enabled.
400 // Enable the DOM storage `Switch`.
401 domStorageEnabledSwitch.setEnabled(true);
403 // Set the DOM storage status. Once minimum API >= 21 we can use a selector as the tint mode instead of specifying different icons.
404 if (domStorageEnabledInt == 1) { // Both JavaScript and DOM storage are enabled.
405 domStorageEnabledSwitch.setChecked(true);
406 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_enabled));
407 } else { // JavaScript is enabled but DOM storage is disabled.
408 // Set the DOM storage switch to off.
409 domStorageEnabledSwitch.setChecked(false);
411 // Set the icon according to the theme.
412 if (MainWebViewActivity.darkTheme) {
413 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_dark));
415 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_light));
418 } else { // JavaScript is disabled.
419 // Disable the DOM storage `Switch`.
420 domStorageEnabledSwitch.setEnabled(false);
422 // Set the checked status of DOM storage.
423 if (domStorageEnabledInt == 1) { // DOM storage is enabled but JavaScript is disabled.
424 domStorageEnabledSwitch.setChecked(true);
425 } else { // Both JavaScript and DOM storage are disabled.
426 domStorageEnabledSwitch.setChecked(false);
429 // Set the icon according to the theme.
430 if (MainWebViewActivity.darkTheme) {
431 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_dark));
433 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_light));
437 // Set the form data status. Once minimum API >= 21 we can use a selector as the tint mode instead of specifying different icons.
438 if (formDataEnabledInt == 1) { // Form data is enabled.
439 formDataEnabledSwitch.setChecked(true);
440 formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_enabled));
441 } else { // Form data is disabled.
442 // Set the form data switch to off.
443 formDataEnabledSwitch.setChecked(false);
445 // Set the icon according to the theme.
446 if (MainWebViewActivity.darkTheme) {
447 formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_disabled_dark));
449 formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_disabled_light));
453 // We need to inflated a `WebView` to get the default user agent.
454 // `@SuppressLint("InflateParams")` removes the warning about using `null` as the `ViewGroup`, which in this case makes sense because we don't want to display `bare_webview` on the screen. `false` does not attach the view to the root.
455 @SuppressLint("InflateParams") View bareWebViewLayout = inflater.inflate(R.layout.bare_webview, null, false);
456 WebView bareWebView = bareWebViewLayout.findViewById(R.id.bare_webview);
457 final String webViewDefaultUserAgentString = bareWebView.getSettings().getUserAgentString();
459 // Get the position of the user agent in `userAgentEntryValuesArrayAdapter`.
460 int userAgentArrayPosition = userAgentEntryValuesArrayAdapter.getPosition(currentUserAgentString);
462 // Set the user agent.
463 if (userAgentArrayPosition == -1) { // We are using a custom `userAgentString`.
464 // Set `userAgentSpinner` to `Custom`.
465 userAgentSpinner.setSelection(userAgentEntryValuesArrayAdapter.getPosition("Custom user agent"));
467 // Hide `userAgentTextView`.
468 userAgentTextView.setVisibility(View.GONE);
470 // Show `customUserAgentEditText` and set `userAgentString` as the text.
471 customUserAgentEditText.setVisibility(View.VISIBLE);
472 customUserAgentEditText.setText(currentUserAgentString);
473 } else{ // We are using one of the preset user agents.
474 // Set the `userAgentSpinner` selection.
475 userAgentSpinner.setSelection(userAgentArrayPosition);
477 // Show `userAgentTextView`.
478 userAgentTextView.setVisibility(View.VISIBLE);
480 // Hide `customUserAgentEditText`.
481 customUserAgentEditText.setVisibility(View.GONE);
483 // Set the user agent text.
484 switch (currentUserAgentString) {
485 case "System default user agent":
486 // Display the user agent text string.
487 switch (defaultUserAgentString) {
488 case "WebView default user agent":
489 // Display the `WebView` default user agent.
490 userAgentTextView.setText(webViewDefaultUserAgentString);
493 case "Custom user agent":
494 // Display the custom user agent.
495 userAgentTextView.setText(defaultCustomUserAgentString);
499 // Display the text from `defaultUserAgentString`.
500 userAgentTextView.setText(defaultUserAgentString);
504 case "WebView default user agent":
505 // Display the `WebView` default user agent.
506 userAgentTextView.setText(webViewDefaultUserAgentString);
510 // Display the text from `currentUserAgentString`.
511 userAgentTextView.setText(currentUserAgentString);
515 // Open the user agent spinner when the `TextView` is clicked.
516 userAgentTextView.setOnClickListener((View v) -> {
517 // Open the user agent spinner.
518 userAgentSpinner.performClick();
521 // Set the selected font size.
522 int fontSizeArrayPosition = fontSizeEntryValuesArrayAdapter.getPosition(String.valueOf(fontSizeInt));
523 fontSizeSpinner.setSelection(fontSizeArrayPosition);
525 // Set the default font size text.
526 int defaultFontSizeArrayPosition = fontSizeEntryValuesArrayAdapter.getPosition(defaultFontSizeString);
527 fontSizeTextView.setText(fontSizeArrayAdapter.getItem(defaultFontSizeArrayPosition));
529 // Set the display options for `fontSizeTextView`.
530 if (fontSizeArrayPosition == 0) { // System default font size is selected. Display `fontSizeTextView`.
531 fontSizeTextView.setVisibility(View.VISIBLE);
532 } else { // A custom font size is specified. Hide `fontSizeTextView`.
533 fontSizeTextView.setVisibility(View.GONE);
536 // Open the font size spinner when the `TextView` is clicked.
537 fontSizeTextView.setOnClickListener((View v) -> {
538 // Open the user agent spinner.
539 fontSizeSpinner.performClick();
542 // Display the website images mode in the spinner.
543 displayWebpageImagesSpinner.setSelection(displayImagesInt);
545 // Set the default display images text.
546 if (defaultDisplayWebpageImagesBoolean) {
547 displayImagesTextView.setText(displayImagesArrayAdapter.getItem(DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_ENABLED));
549 displayImagesTextView.setText(displayImagesArrayAdapter.getItem(DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_DISABLED));
552 // Set the display website images icon and `TextView` settings. Once minimum API >= 21 we can use a selector as the tint mode instead of specifying different icons.
553 switch (displayImagesInt) {
554 case DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_SYSTEM_DEFAULT:
555 if (defaultDisplayWebpageImagesBoolean) { // Display webpage images enabled by default.
556 // Set the icon according to the theme.
557 if (MainWebViewActivity.darkTheme) {
558 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_dark));
560 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_light));
562 } else { // Display webpage images disabled by default.
563 // Set the icon according to the theme.
564 if (MainWebViewActivity.darkTheme) {
565 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_dark));
567 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_light));
571 // Show `displayImagesTextView`.
572 displayImagesTextView.setVisibility(View.VISIBLE);
575 case DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_ENABLED:
576 // Set the icon according to the theme.
577 if (MainWebViewActivity.darkTheme) {
578 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_dark));
580 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_light));
583 // Hide `displayImagesTextView`.
584 displayImagesTextView.setVisibility(View.GONE);
587 case DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_DISABLED:
588 // Set the icon according to the theme.
589 if (MainWebViewActivity.darkTheme) {
590 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_dark));
592 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_light));
595 // Hide `displayImagesTextView`.
596 displayImagesTextView.setVisibility(View.GONE);
600 // Open the display images spinner when the `TextView` is clicked.
601 displayImagesTextView.setOnClickListener((View v) -> {
602 // Open the user agent spinner.
603 displayWebpageImagesSpinner.performClick();
606 // Display the night mode in the spinner.
607 nightModeSpinner.setSelection(nightModeInt);
609 // Set the default night mode text.
610 if (defaultNightModeBoolean) {
611 nightModeTextView.setText(nightModeArrayAdapter.getItem(DomainsDatabaseHelper.NIGHT_MODE_ENABLED));
613 nightModeTextView.setText(nightModeArrayAdapter.getItem(DomainsDatabaseHelper.NIGHT_MODE_DISABLED));
616 // Set the night mode icon and `TextView` settings. Once minimum API >= 21 we can use a selector as the tint mode instead of specifying different icons.
617 switch (displayImagesInt) {
618 case DomainsDatabaseHelper.NIGHT_MODE_SYSTEM_DEFAULT:
619 if (defaultNightModeBoolean) { // Night mode enabled by default.
620 // Set the icon according to the theme.
621 if (MainWebViewActivity.darkTheme) {
622 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_dark));
624 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_light));
626 } else { // Night mode disabled by default.
627 // Set the icon according to the theme.
628 if (MainWebViewActivity.darkTheme) {
629 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_dark));
631 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_light));
635 // Show `nightModeTextView`.
636 nightModeTextView.setVisibility(View.VISIBLE);
639 case DomainsDatabaseHelper.NIGHT_MODE_ENABLED:
640 // Set the icon according to the theme.
641 if (MainWebViewActivity.darkTheme) {
642 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_dark));
644 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_light));
647 // Hide `nightModeTextView`.
648 nightModeTextView.setVisibility(View.GONE);
651 case DomainsDatabaseHelper.NIGHT_MODE_DISABLED:
652 // Set the icon according to the theme.
653 if (MainWebViewActivity.darkTheme) {
654 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_dark));
656 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_light));
659 // Hide `nightModeTextView`.
660 nightModeTextView.setVisibility(View.GONE);
664 // Open the night mode spinner when the `TextView` is clicked.
665 nightModeTextView.setOnClickListener((View v) -> {
666 // Open the user agent spinner.
667 nightModeSpinner.performClick();
670 // Set the pinned SSL certificate icon.
671 if (pinnedSslCertificateInt == 1) { // Pinned SSL certificate is enabled. Once minimum API >= 21 we can use a selector as the tint mode instead of specifying different icons.
673 pinnedSslCertificateSwitch.setChecked(true);
675 // Set the icon according to the theme.
676 if (MainWebViewActivity.darkTheme) {
677 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_dark));
679 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_light));
681 } else { // Pinned SSL certificate is disabled.
682 // Uncheck the switch.
683 pinnedSslCertificateSwitch.setChecked(false);
685 // Set the icon according to the theme.
686 if (MainWebViewActivity.darkTheme) {
687 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_dark));
689 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_light));
693 // Store the current date.
694 Date currentDate = Calendar.getInstance().getTime();
696 // Setup the `StringBuilders` to display the general certificate information in blue. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
697 savedSslCertificateIssuedToONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), savedSslCertificateIssuedToONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
698 savedSslCertificateIssuedToUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), savedSslCertificateIssuedToUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
699 savedSslCertificateIssuedByCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), savedSslCertificateIssuedByCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
700 savedSslCertificateIssuedByONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), savedSslCertificateIssuedByONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
701 savedSslCertificateIssuedByUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), savedSslCertificateIssuedByUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
703 // Check the certificate `Common Name` against the domain name.
704 boolean savedSSlCertificateCommonNameMatchesDomainName = checkDomainNameAgainstCertificate(domainNameString, savedSslCertificateIssuedToCNameString);
706 // Format the `issuedToCommonName` color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
707 if (savedSSlCertificateCommonNameMatchesDomainName) {
708 savedSslCertificateIssuedToCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), savedSslCertificateIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
710 savedSslCertificateIssuedToCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), savedSslCertificateIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
713 // Format the start date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
714 if ((savedSslCertificateStartDate != null) && savedSslCertificateStartDate.after(currentDate)) { // The certificate start date is in the future.
715 savedSslCertificateStartDateStringBuilder.setSpan(redColorSpan, startDateLabel.length(), savedSslCertificateStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
716 } else { // The certificate start date is in the past.
717 savedSslCertificateStartDateStringBuilder.setSpan(blueColorSpan, startDateLabel.length(), savedSslCertificateStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
720 // Format the end date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
721 if ((savedSslCertificateEndDate != null) && savedSslCertificateEndDate.before(currentDate)) { // The certificate end date is in the past.
722 savedSslCertificateEndDateStringBuilder.setSpan(redColorSpan, endDateLabel.length(), savedSslCertificateEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
723 } else { // The certificate end date is in the future.
724 savedSslCertificateEndDateStringBuilder.setSpan(blueColorSpan, endDateLabel.length(), savedSslCertificateEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
727 // Display the current website SSL certificate strings.
728 savedSslCertificateIssuedToCNameTextView.setText(savedSslCertificateIssuedToCNameStringBuilder);
729 savedSslCertificateIssuedToONameTextView.setText(savedSslCertificateIssuedToONameStringBuilder);
730 savedSslCertificateIssuedToUNameTextView.setText(savedSslCertificateIssuedToUNameStringBuilder);
731 savedSslCertificateIssuedByCNameTextView.setText(savedSslCertificateIssuedByCNameStringBuilder);
732 savedSslCertificateIssuedByONameTextView.setText(savedSslCertificateIssuedByONameStringBuilder);
733 savedSslCertificateIssuedByUNameTextView.setText(savedSslCertificateIssuedByUNameStringBuilder);
734 savedSslCertificateStartDateTextView.setText(savedSslCertificateStartDateStringBuilder);
735 savedSslCertificateEndDateTextView.setText(savedSslCertificateEndDateStringBuilder);
737 // Populate the current website SSL certificate if there is one.
738 if (currentWebsiteSslCertificate != null) {
739 // Get the strings from the SSL certificate.
740 String currentWebsiteCertificateIssuedToCNameString = currentWebsiteSslCertificate.getIssuedTo().getCName();
741 String currentWebsiteCertificateIssuedToONameString = currentWebsiteSslCertificate.getIssuedTo().getOName();
742 String currentWebsiteCertificateIssuedToUNameString = currentWebsiteSslCertificate.getIssuedTo().getUName();
743 String currentWebsiteCertificateIssuedByCNameString = currentWebsiteSslCertificate.getIssuedBy().getCName();
744 String currentWebsiteCertificateIssuedByONameString = currentWebsiteSslCertificate.getIssuedBy().getOName();
745 String currentWebsiteCertificateIssuedByUNameString = currentWebsiteSslCertificate.getIssuedBy().getUName();
746 Date currentWebsiteCertificateStartDate = currentWebsiteSslCertificate.getValidNotBeforeDate();
747 Date currentWebsiteCertificateEndDate = currentWebsiteSslCertificate.getValidNotAfterDate();
749 // Create a `SpannableStringBuilder` for each `TextView` that needs multiple colors of text.
750 SpannableStringBuilder currentWebsiteCertificateIssuedToCNameStringBuilder = new SpannableStringBuilder(cNameLabel + currentWebsiteCertificateIssuedToCNameString);
751 SpannableStringBuilder currentWebsiteCertificateIssuedToONameStringBuilder = new SpannableStringBuilder(oNameLabel + currentWebsiteCertificateIssuedToONameString);
752 SpannableStringBuilder currentWebsiteCertificateIssuedToUNameStringBuilder = new SpannableStringBuilder(uNameLabel + currentWebsiteCertificateIssuedToUNameString);
753 SpannableStringBuilder currentWebsiteCertificateIssuedByCNameStringBuilder = new SpannableStringBuilder(cNameLabel + currentWebsiteCertificateIssuedByCNameString);
754 SpannableStringBuilder currentWebsiteCertificateIssuedByONameStringBuilder = new SpannableStringBuilder(oNameLabel + currentWebsiteCertificateIssuedByONameString);
755 SpannableStringBuilder currentWebsiteCertificateIssuedByUNameStringBuilder = new SpannableStringBuilder(uNameLabel + currentWebsiteCertificateIssuedByUNameString);
756 SpannableStringBuilder currentWebsiteCertificateStartDateStringBuilder = new SpannableStringBuilder(startDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(currentWebsiteCertificateStartDate));
757 SpannableStringBuilder currentWebsiteCertificateEndDateStringBuilder = new SpannableStringBuilder(endDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(currentWebsiteCertificateEndDate));
759 // Setup the `StringBuilders` to display the general certificate information in blue. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
760 currentWebsiteCertificateIssuedToONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), currentWebsiteCertificateIssuedToONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
761 currentWebsiteCertificateIssuedToUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), currentWebsiteCertificateIssuedToUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
762 currentWebsiteCertificateIssuedByCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), currentWebsiteCertificateIssuedByCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
763 currentWebsiteCertificateIssuedByONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), currentWebsiteCertificateIssuedByONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
764 currentWebsiteCertificateIssuedByUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), currentWebsiteCertificateIssuedByUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
766 // Check the certificate `Common Name` against the domain name.
767 boolean currentWebsiteCertificateCommonNameMatchesDomainName = checkDomainNameAgainstCertificate(domainNameString, currentWebsiteCertificateIssuedToCNameString);
769 // Format the `issuedToCommonName` color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
770 if (currentWebsiteCertificateCommonNameMatchesDomainName) {
771 currentWebsiteCertificateIssuedToCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), currentWebsiteCertificateIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
773 currentWebsiteCertificateIssuedToCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), currentWebsiteCertificateIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
776 // Format the start date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
777 if (currentWebsiteCertificateStartDate.after(currentDate)) { // The certificate start date is in the future.
778 currentWebsiteCertificateStartDateStringBuilder.setSpan(redColorSpan, startDateLabel.length(), currentWebsiteCertificateStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
779 } else { // The certificate start date is in the past.
780 currentWebsiteCertificateStartDateStringBuilder.setSpan(blueColorSpan, startDateLabel.length(), currentWebsiteCertificateStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
783 // Format the end date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
784 if (currentWebsiteCertificateEndDate.before(currentDate)) { // The certificate end date is in the past.
785 currentWebsiteCertificateEndDateStringBuilder.setSpan(redColorSpan, endDateLabel.length(), currentWebsiteCertificateEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
786 } else { // The certificate end date is in the future.
787 currentWebsiteCertificateEndDateStringBuilder.setSpan(blueColorSpan, endDateLabel.length(), currentWebsiteCertificateEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
790 // Display the current website SSL certificate strings.
791 currentWebsiteCertificateIssuedToCNameTextView.setText(currentWebsiteCertificateIssuedToCNameStringBuilder);
792 currentWebsiteCertificateIssuedToONameTextView.setText(currentWebsiteCertificateIssuedToONameStringBuilder);
793 currentWebsiteCertificateIssuedToUNameTextView.setText(currentWebsiteCertificateIssuedToUNameStringBuilder);
794 currentWebsiteCertificateIssuedByCNameTextView.setText(currentWebsiteCertificateIssuedByCNameStringBuilder);
795 currentWebsiteCertificateIssuedByONameTextView.setText(currentWebsiteCertificateIssuedByONameStringBuilder);
796 currentWebsiteCertificateIssuedByUNameTextView.setText(currentWebsiteCertificateIssuedByUNameStringBuilder);
797 currentWebsiteCertificateStartDateTextView.setText(currentWebsiteCertificateStartDateStringBuilder);
798 currentWebsiteCertificateEndDateTextView.setText(currentWebsiteCertificateEndDateStringBuilder);
801 // Set the initial display status for the SSL certificates.
802 if (pinnedSslCertificateSwitch.isChecked()) {
803 // Set the visibility of the saved SSL certificate.
804 if (savedSslCertificateIssuedToCNameString == null) {
805 savedSslCertificateLinearLayout.setVisibility(View.GONE);
807 savedSslCertificateLinearLayout.setVisibility(View.VISIBLE);
810 // Set the visibility of the current website SSL certificate.
811 if (currentWebsiteSslCertificate == null) {
812 // Hide the SSL certificate.
813 currentWebsiteCertificateLinearLayout.setVisibility(View.GONE);
815 // Show the instruction.
816 noCurrentWebsiteCertificateTextView.setVisibility(View.VISIBLE);
818 // Show the SSL certificate.
819 currentWebsiteCertificateLinearLayout.setVisibility(View.VISIBLE);
821 // Hide the instruction.
822 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
825 // Set the status of the radio buttons.
826 if (savedSslCertificateLinearLayout.getVisibility() == View.VISIBLE) { // The saved SSL certificate is displayed.
827 savedSslCertificateRadioButton.setChecked(true);
828 currentWebsiteCertificateRadioButton.setChecked(false);
829 } else if (currentWebsiteCertificateLinearLayout.getVisibility() == View.VISIBLE) { // The saved SSL certificate is hidden but the current website SSL certificate is visible.
830 currentWebsiteCertificateRadioButton.setChecked(true);
831 savedSslCertificateRadioButton.setChecked(false);
832 } else { // Neither SSL certificate is visible.
833 savedSslCertificateRadioButton.setChecked(false);
834 currentWebsiteCertificateRadioButton.setChecked(false);
836 } else { // `pinnedSslCertificateSwitch` is not checked.
837 // Hide the SSl certificates and instructions.
838 savedSslCertificateLinearLayout.setVisibility(View.GONE);
839 currentWebsiteCertificateLinearLayout.setVisibility(View.GONE);
840 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
842 // Uncheck the radio buttons.
843 savedSslCertificateRadioButton.setChecked(false);
844 currentWebsiteCertificateRadioButton.setChecked(false);
848 // Set the `javaScriptEnabledSwitch` `OnCheckedChangeListener()`.
849 javaScriptEnabledSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
850 if (isChecked) { // JavaScript is enabled.
851 // Update the JavaScript icon.
852 javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.javascript_enabled));
854 // Enable the DOM storage `Switch`.
855 domStorageEnabledSwitch.setEnabled(true);
857 // Update the DOM storage icon.
858 if (domStorageEnabledSwitch.isChecked()) { // DOM storage is enabled.
859 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_enabled));
860 } else { // DOM storage is disabled.
861 // Set the icon according to the theme.
862 if (MainWebViewActivity.darkTheme) {
863 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_dark));
865 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_light));
868 } else { // JavaScript is disabled.
869 // Update the JavaScript icon.
870 javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.privacy_mode));
872 // Disable the DOM storage `Switch`.
873 domStorageEnabledSwitch.setEnabled(false);
875 // Set the DOM storage icon according to the theme.
876 if (MainWebViewActivity.darkTheme) {
877 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_dark));
879 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_light));
884 // Set the `firstPartyCookiesEnabledSwitch` `OnCheckedChangeListener()`.
885 firstPartyCookiesEnabledSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
886 if (isChecked) { // First-party cookies are enabled.
887 // Update the first-party cookies icon.
888 firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_enabled));
890 // Enable the third-party cookies `Switch`.
891 thirdPartyCookiesEnabledSwitch.setEnabled(true);
893 // Update the third-party cookies icon.
894 if (thirdPartyCookiesEnabledSwitch.isChecked()) { // Third-party cookies are enabled.
895 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_warning));
896 } else { // Third-party cookies are disabled.
897 // Set the third-party cookies icon according to the theme.
898 if (MainWebViewActivity.darkTheme) {
899 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_dark));
901 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_light));
904 } else { // First-party cookies are disabled.
905 // Update the first-party cookies icon according to the theme.
906 if (MainWebViewActivity.darkTheme) {
907 firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_dark));
909 firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_light));
912 // Disable the third-party cookies `Switch`.
913 thirdPartyCookiesEnabledSwitch.setEnabled(false);
915 // Set the third-party cookies icon according to the theme.
916 if (MainWebViewActivity.darkTheme) {
917 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_ghosted_dark));
919 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_ghosted_light));
924 // Set the `thirdPartyCookiesEnabledSwitch` `OnCheckedChangeListener()`.
925 thirdPartyCookiesEnabledSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
928 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_warning));
930 // Update the third-party cookies icon according to the theme.
931 if (MainWebViewActivity.darkTheme) {
932 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_dark));
934 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_light));
939 // Set the `domStorageEnabledSwitch` `OnCheckedChangeListener()`.
940 domStorageEnabledSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
943 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_enabled));
945 // Set the icon according to the theme.
946 if (MainWebViewActivity.darkTheme) {
947 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_dark));
949 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_light));
954 // Set the `formDataEnabledSwitch` `OnCheckedChangeListener()`.
955 formDataEnabledSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
958 formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_enabled));
960 // Set the icon according to the theme.
961 if (MainWebViewActivity.darkTheme) {
962 formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_disabled_dark));
964 formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_disabled_light));
969 // Set the `userAgentSpinner` `onItemClickListener()`.
970 userAgentSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
972 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
973 // Store the new user agent string.
974 String newUserAgentString = resources.getStringArray(R.array.domain_settings_user_agent_entry_values)[position];
976 // Set the new user agent.
977 switch (newUserAgentString) {
978 case "System default user agent":
979 // Show `userAgentTextView`.
980 userAgentTextView.setVisibility(View.VISIBLE);
982 // Hide `customUserAgentEditText`.
983 customUserAgentEditText.setVisibility(View.GONE);
985 // Set the user text.
986 switch (defaultUserAgentString) {
987 case "WebView default user agent":
988 // Display the `WebView` default user agent.
989 userAgentTextView.setText(webViewDefaultUserAgentString);
992 case "Custom user agent":
993 // Display the custom user agent.
994 userAgentTextView.setText(defaultCustomUserAgentString);
998 // Display the text from `defaultUserAgentString`.
999 userAgentTextView.setText(defaultUserAgentString);
1003 case "WebView default user agent":
1004 // Show `userAgentTextView` and set the text.
1005 userAgentTextView.setVisibility(View.VISIBLE);
1006 userAgentTextView.setText(webViewDefaultUserAgentString);
1008 // Hide `customUserAgentEditText`.
1009 customUserAgentEditText.setVisibility(View.GONE);
1012 case "Custom user agent":
1013 // Hide `userAgentTextView`.
1014 userAgentTextView.setVisibility(View.GONE);
1016 // Show `customUserAgentEditText` and set `userAgentString` as the text.
1017 customUserAgentEditText.setVisibility(View.VISIBLE);
1018 customUserAgentEditText.setText(currentUserAgentString);
1022 // Show `userAgentTextView` and set the text.
1023 userAgentTextView.setVisibility(View.VISIBLE);
1024 userAgentTextView.setText(newUserAgentString);
1026 // Hide `customUserAgentEditText`.
1027 customUserAgentEditText.setVisibility(View.GONE);
1032 public void onNothingSelected(AdapterView<?> parent) {
1037 // Set the `fontSizeSpinner` `onItemSelectedListener()`.
1038 fontSizeSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1040 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1041 // Update the display options for `fontSizeTextView`.
1042 if (position == 0) { // System default font size has been selected. Display `fontSizeTextView`.
1043 fontSizeTextView.setVisibility(View.VISIBLE);
1044 } else { // A custom font size has been selected. Hide `fontSizeTextView`.
1045 fontSizeTextView.setVisibility(View.GONE);
1050 public void onNothingSelected(AdapterView<?> parent) {
1055 // Set the `displayWebpageImagesSpinner` `onItemSelectedListener()`.
1056 displayWebpageImagesSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1058 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1059 // Update the icon and the visibility of `displayImagesTextView`.
1061 case DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_SYSTEM_DEFAULT:
1062 if (defaultDisplayWebpageImagesBoolean) {
1063 // Set the icon according to the theme.
1064 if (MainWebViewActivity.darkTheme) {
1065 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_dark));
1067 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_light));
1070 // Set the icon according to the theme.
1071 if (MainWebViewActivity.darkTheme) {
1072 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_dark));
1074 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_light));
1078 // Show `displayImagesTextView`.
1079 displayImagesTextView.setVisibility(View.VISIBLE);
1082 case DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_ENABLED:
1083 // Set the icon according to the theme.
1084 if (MainWebViewActivity.darkTheme) {
1085 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_dark));
1087 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_light));
1090 // Hide `displayImagesTextView`.
1091 displayImagesTextView.setVisibility(View.GONE);
1094 case DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_DISABLED:
1095 // Set the icon according to the theme.
1096 if (MainWebViewActivity.darkTheme) {
1097 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_dark));
1099 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_light));
1102 // Hide `displayImagesTextView`.
1103 displayImagesTextView.setVisibility(View.GONE);
1109 public void onNothingSelected(AdapterView<?> parent) {
1114 // Set the `nightModeSpinner` `onItemSelectedListener()`.
1115 nightModeSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1117 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1118 // Update the icon and the visibility of `nightModeTextView`. Once minimum API >= 21 we can use a selector as the tint mode instead of specifying different icons.
1120 case DomainsDatabaseHelper.NIGHT_MODE_SYSTEM_DEFAULT:
1121 if (defaultNightModeBoolean) { // Night mode enabled by default.
1122 // Set the icon according to the theme.
1123 if (MainWebViewActivity.darkTheme) {
1124 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_dark));
1126 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_light));
1128 } else { // Night mode disabled by default.
1129 // Set the icon according to the theme.
1130 if (MainWebViewActivity.darkTheme) {
1131 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_dark));
1133 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_light));
1137 // Show `nightModeTextView`.
1138 nightModeTextView.setVisibility(View.VISIBLE);
1141 case DomainsDatabaseHelper.NIGHT_MODE_ENABLED:
1142 // Set the icon according to the theme.
1143 if (MainWebViewActivity.darkTheme) {
1144 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_dark));
1146 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_light));
1149 // Hide `nightModeTextView`.
1150 nightModeTextView.setVisibility(View.GONE);
1153 case DomainsDatabaseHelper.NIGHT_MODE_DISABLED:
1154 // Set the icon according to the theme.
1155 if (MainWebViewActivity.darkTheme) {
1156 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_dark));
1158 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_light));
1161 // Hide `nightModeTextView`.
1162 nightModeTextView.setVisibility(View.GONE);
1166 // Create a `boolean` to store the current night mode setting.
1167 boolean currentNightModeEnabled = (position == DomainsDatabaseHelper.NIGHT_MODE_ENABLED) || ((position == DomainsDatabaseHelper.NIGHT_MODE_SYSTEM_DEFAULT) && defaultNightModeBoolean);
1169 // Disable the JavaScript `Switch` if night mode is enabled.
1170 if (currentNightModeEnabled) {
1171 javaScriptEnabledSwitch.setEnabled(false);
1173 javaScriptEnabledSwitch.setEnabled(true);
1176 // Update the JavaScript icon.
1177 if ((javaScriptEnabledInt == 1) || currentNightModeEnabled) {
1178 javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.javascript_enabled));
1180 javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.privacy_mode));
1183 // Update the DOM storage status.
1184 if ((javaScriptEnabledInt == 1) || currentNightModeEnabled) { // JavaScript is enabled.
1185 // Enable the DOM storage `Switch`.
1186 domStorageEnabledSwitch.setEnabled(true);
1188 // Set the DOM storage status. Once minimum API >= 21 we can use a selector as the tint mode instead of specifying different icons.
1189 if (domStorageEnabledInt == 1) { // Both JavaScript and DOM storage are enabled.
1190 domStorageEnabledSwitch.setChecked(true);
1191 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_enabled));
1192 } else { // JavaScript is enabled but DOM storage is disabled.
1193 // Set the DOM storage switch to off.
1194 domStorageEnabledSwitch.setChecked(false);
1196 // Set the icon according to the theme.
1197 if (MainWebViewActivity.darkTheme) {
1198 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_dark));
1200 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_light));
1203 } else { // JavaScript is disabled.
1204 // Disable the DOM storage `Switch`.
1205 domStorageEnabledSwitch.setEnabled(false);
1207 // Set the checked status of DOM storage.
1208 if (domStorageEnabledInt == 1) { // DOM storage is enabled but JavaScript is disabled.
1209 domStorageEnabledSwitch.setChecked(true);
1210 } else { // Both JavaScript and DOM storage are disabled.
1211 domStorageEnabledSwitch.setChecked(false);
1214 // Set the icon according to the theme.
1215 if (MainWebViewActivity.darkTheme) {
1216 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_dark));
1218 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_light));
1224 public void onNothingSelected(AdapterView<?> parent) {
1229 // Set the `pinnedSSLCertificateSwitch` `onCheckedChangeListener()`.
1230 pinnedSslCertificateSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1232 if (isChecked) { // Pinned SSL certificate is enabled.
1233 // Set the icon according to the theme.
1234 if (MainWebViewActivity.darkTheme) {
1235 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_dark));
1237 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_light));
1240 // Update the visibility of the saved SSL certificate.
1241 if (savedSslCertificateIssuedToCNameString == null) {
1242 savedSslCertificateLinearLayout.setVisibility(View.GONE);
1244 savedSslCertificateLinearLayout.setVisibility(View.VISIBLE);
1247 // Update the visibility of the current website SSL certificate.
1248 if (currentWebsiteSslCertificate == null) {
1249 // Hide the SSL certificate.
1250 currentWebsiteCertificateLinearLayout.setVisibility(View.GONE);
1252 // Show the instruction.
1253 noCurrentWebsiteCertificateTextView.setVisibility(View.VISIBLE);
1255 // Show the SSL certificate.
1256 currentWebsiteCertificateLinearLayout.setVisibility(View.VISIBLE);
1258 // Hide the instruction.
1259 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
1262 // Set the status of the radio buttons.
1263 if (savedSslCertificateLinearLayout.getVisibility() == View.VISIBLE) { // The saved SSL certificate is displayed.
1264 savedSslCertificateRadioButton.setChecked(true);
1265 currentWebsiteCertificateRadioButton.setChecked(false);
1266 } else if (currentWebsiteCertificateLinearLayout.getVisibility() == View.VISIBLE) { // The saved SSL certificate is hidden but the current website SSL certificate is visible.
1267 currentWebsiteCertificateRadioButton.setChecked(true);
1268 savedSslCertificateRadioButton.setChecked(false);
1269 } else { // Neither SSL certificate is visible.
1270 savedSslCertificateRadioButton.setChecked(false);
1271 currentWebsiteCertificateRadioButton.setChecked(false);
1273 } else { // Pinned SSL certificate is disabled.
1274 // Set the icon according to the theme.
1275 if (MainWebViewActivity.darkTheme) {
1276 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_dark));
1278 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_light));
1281 // Hide the SSl certificates and instructions.
1282 savedSslCertificateLinearLayout.setVisibility(View.GONE);
1283 currentWebsiteCertificateLinearLayout.setVisibility(View.GONE);
1284 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
1286 // Uncheck the radio buttons.
1287 savedSslCertificateRadioButton.setChecked(false);
1288 currentWebsiteCertificateRadioButton.setChecked(false);
1292 savedSslCertificateLinearLayout.setOnClickListener((View v) -> {
1293 savedSslCertificateRadioButton.setChecked(true);
1294 currentWebsiteCertificateRadioButton.setChecked(false);
1297 savedSslCertificateRadioButton.setOnClickListener((View v) -> {
1298 savedSslCertificateRadioButton.setChecked(true);
1299 currentWebsiteCertificateRadioButton.setChecked(false);
1302 currentWebsiteCertificateLinearLayout.setOnClickListener((View v) -> {
1303 currentWebsiteCertificateRadioButton.setChecked(true);
1304 savedSslCertificateRadioButton.setChecked(false);
1307 currentWebsiteCertificateRadioButton.setOnClickListener((View v) -> {
1308 currentWebsiteCertificateRadioButton.setChecked(true);
1309 savedSslCertificateRadioButton.setChecked(false);
1312 return domainSettingsView;
1315 private boolean checkDomainNameAgainstCertificate(String domainName, String certificateCommonName) {
1316 // Initialize `domainNamesMatch`.
1317 boolean domainNamesMatch = false;
1319 // Check if the domains match.
1320 if (domainName.equals(certificateCommonName)) {
1321 domainNamesMatch = true;
1324 // Check various wildcard permutations if `domainName` and `certificateCommonName` are not empty. `noinspection ConstantCondition` removes Android Studio's incorrect lint warning that `domainName` can never be `null`.
1325 //noinspection ConstantConditions
1326 if ((domainName != null) && (certificateCommonName != null)) {
1327 // If `domainName` starts with a wildcard, check the base domain against all the subdomains of `certificateCommonName`.
1328 if (!domainNamesMatch && domainName.startsWith("*.") && (domainName.length() > 2)) {
1329 // Remove the initial `*.`.
1330 String baseDomainName = domainName.substring(2);
1332 // Setup a copy of `certificateCommonName` to test subdomains.
1333 String certificateCommonNameSubdomain = certificateCommonName;
1335 // Check all the subdomains in `certificateCommonNameSubdomain` against `baseDomainName`.
1336 while (!domainNamesMatch && certificateCommonNameSubdomain.contains(".")) { // Stop checking if we know that `domainNamesMatch` is `true` or if we run out of `.`.
1337 // Test the `certificateCommonNameSubdomain` against `baseDomainName`.
1338 if (certificateCommonNameSubdomain.equals(baseDomainName)) {
1339 domainNamesMatch = true;
1342 // Strip out the lowest subdomain of `certificateCommonNameSubdomain`.
1344 certificateCommonNameSubdomain = certificateCommonNameSubdomain.substring(certificateCommonNameSubdomain.indexOf(".") + 1);
1345 } catch (IndexOutOfBoundsException e) { // `certificateCommonNameSubdomain` ends with `.`.
1346 certificateCommonNameSubdomain = "";
1351 // If `certificateCommonName` starts with a wildcard, check the base common name against all the subdomains of `domainName`.
1352 if (!domainNamesMatch && certificateCommonName.startsWith("*.") && (certificateCommonName.length() > 2)) {
1353 // Remove the initial `*.`.
1354 String baseCertificateCommonName = certificateCommonName.substring(2);
1356 // Setup a copy of `domainName` to test subdomains.
1357 String domainNameSubdomain = domainName;
1359 // Check all the subdomains in `domainNameSubdomain` against `baseCertificateCommonName`.
1360 while (!domainNamesMatch && domainNameSubdomain.contains(".") && (domainNameSubdomain.length() > 2)) {
1361 // Test the `domainNameSubdomain` against `baseCertificateCommonName`.
1362 if (domainNameSubdomain.equals(baseCertificateCommonName)) {
1363 domainNamesMatch = true;
1366 // Strip out the lowest subdomain of `domainNameSubdomain`.
1368 domainNameSubdomain = domainNameSubdomain.substring(domainNameSubdomain.indexOf(".") + 1);
1369 } catch (IndexOutOfBoundsException e) { // `domainNameSubdomain` ends with `.`.
1370 domainNameSubdomain = "";
1375 // If both names start with a wildcard, check if the root of one contains the root of the other.
1376 if (!domainNamesMatch && domainName.startsWith("*.") && (domainName.length() > 2) && certificateCommonName.startsWith("*.") && (certificateCommonName.length() > 2)) {
1377 // Remove the wildcards.
1378 String rootDomainName = domainName.substring(2);
1379 String rootCertificateCommonName = certificateCommonName.substring(2);
1381 // Check if one name ends with the contents of the other. If so, there will be overlap in the their wildcard subdomains.
1382 if (rootDomainName.endsWith(rootCertificateCommonName) || rootCertificateCommonName.endsWith(rootDomainName)) {
1383 domainNamesMatch = true;
1388 return domainNamesMatch;