2 * Copyright © 2017-2019 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.os.Build;
28 import android.os.Bundle;
29 import android.preference.PreferenceManager;
30 import android.text.Editable;
31 import android.text.SpannableStringBuilder;
32 import android.text.Spanned;
33 import android.text.TextWatcher;
34 import android.text.style.ForegroundColorSpan;
35 import android.view.LayoutInflater;
36 import android.view.View;
37 import android.view.ViewGroup;
38 import android.webkit.WebView;
39 import android.widget.AdapterView;
40 import android.widget.ArrayAdapter;
41 import android.widget.CompoundButton;
42 import android.widget.EditText;
43 import android.widget.ImageView;
44 import android.widget.LinearLayout;
45 import android.widget.RadioButton;
46 import android.widget.Spinner;
47 import android.widget.Switch;
48 import android.widget.TextView;
50 import androidx.annotation.NonNull;
51 import androidx.cardview.widget.CardView;
52 import androidx.fragment.app.Fragment; // The AndroidX fragment must be used until minimum API >= 23. Otherwise `getContext()` does not work.
54 import com.stoutner.privacybrowser.R;
55 import com.stoutner.privacybrowser.activities.DomainsActivity;
56 import com.stoutner.privacybrowser.activities.MainWebViewActivity;
57 import com.stoutner.privacybrowser.helpers.DomainsDatabaseHelper;
59 import java.text.DateFormat;
60 import java.util.Calendar;
61 import java.util.Date;
63 public class DomainSettingsFragment extends Fragment {
64 // `DATABASE_ID` is used by activities calling this fragment.
65 public static final String DATABASE_ID = "database_id";
67 // `databaseId` is public static so it can be accessed from `DomainsActivity`. It is also used in `onCreate()` and `onCreateView()`.
68 public static int databaseId;
71 public void onCreate(Bundle savedInstanceState) {
72 // Run the default commands.
73 super.onCreate(savedInstanceState);
75 // Remove the lint warning that `getArguments` might be null.
76 assert getArguments() != null;
78 // Store the database id in `databaseId`.
79 databaseId = getArguments().getInt(DATABASE_ID);
82 // The deprecated `getDrawable()` must be used until the minimum API >= 21.
84 public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
85 // Inflate `domain_settings_fragment`. `false` does not attach it to the root `container`.
86 View domainSettingsView = inflater.inflate(R.layout.domain_settings_fragment, container, false);
88 // Get a handle for the context and the resources.
89 Context context = getContext();
90 Resources resources = getResources();
92 // Get a handle for the shared preference.
93 SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
95 // Store the default settings.
96 String defaultUserAgentName = sharedPreferences.getString("user_agent", getString(R.string.user_agent_default_value));
97 String defaultCustomUserAgentString = sharedPreferences.getString("custom_user_agent", getString(R.string.custom_user_agent_default_value));
98 String defaultFontSizeString = sharedPreferences.getString("font_size", getString(R.string.font_size_default_value));
99 boolean defaultSwipeToRefresh = sharedPreferences.getBoolean("swipe_to_refresh", true);
100 boolean defaultNightMode = sharedPreferences.getBoolean("night_mode", false);
101 boolean defaultDisplayWebpageImages = sharedPreferences.getBoolean("display_webpage_images", true);
102 boolean darkTheme = sharedPreferences.getBoolean("dark_theme", false);
104 // Get handles for the views in the fragment.
105 EditText domainNameEditText = domainSettingsView.findViewById(R.id.domain_settings_name_edittext);
106 Switch javaScriptEnabledSwitch = domainSettingsView.findViewById(R.id.javascript_switch);
107 ImageView javaScriptImageView = domainSettingsView.findViewById(R.id.javascript_imageview);
108 Switch firstPartyCookiesEnabledSwitch = domainSettingsView.findViewById(R.id.first_party_cookies_switch);
109 ImageView firstPartyCookiesImageView = domainSettingsView.findViewById(R.id.first_party_cookies_imageview);
110 LinearLayout thirdPartyCookiesLinearLayout = domainSettingsView.findViewById(R.id.third_party_cookies_linearlayout);
111 Switch thirdPartyCookiesEnabledSwitch = domainSettingsView.findViewById(R.id.third_party_cookies_switch);
112 ImageView thirdPartyCookiesImageView = domainSettingsView.findViewById(R.id.third_party_cookies_imageview);
113 Switch domStorageEnabledSwitch = domainSettingsView.findViewById(R.id.dom_storage_switch);
114 ImageView domStorageImageView = domainSettingsView.findViewById(R.id.dom_storage_imageview);
115 Switch formDataEnabledSwitch = domainSettingsView.findViewById(R.id.form_data_switch); // The form data views can be remove once the minimum API >= 26.
116 ImageView formDataImageView = domainSettingsView.findViewById(R.id.form_data_imageview); // The form data views can be remove once the minimum API >= 26.
117 Switch easyListSwitch = domainSettingsView.findViewById(R.id.easylist_switch);
118 ImageView easyListImageView = domainSettingsView.findViewById(R.id.easylist_imageview);
119 Switch easyPrivacySwitch = domainSettingsView.findViewById(R.id.easyprivacy_switch);
120 ImageView easyPrivacyImageView = domainSettingsView.findViewById(R.id.easyprivacy_imageview);
121 Switch fanboysAnnoyanceListSwitch = domainSettingsView.findViewById(R.id.fanboys_annoyance_list_switch);
122 ImageView fanboysAnnoyanceListImageView = domainSettingsView.findViewById(R.id.fanboys_annoyance_list_imageview);
123 Switch fanboysSocialBlockingListSwitch = domainSettingsView.findViewById(R.id.fanboys_social_blocking_list_switch);
124 ImageView fanboysSocialBlockingListImageView = domainSettingsView.findViewById(R.id.fanboys_social_blocking_list_imageview);
125 Switch ultraPrivacySwitch = domainSettingsView.findViewById(R.id.ultraprivacy_switch);
126 ImageView ultraPrivacyImageView = domainSettingsView.findViewById(R.id.ultraprivacy_imageview);
127 Switch blockAllThirdPartyRequestsSwitch = domainSettingsView.findViewById(R.id.block_all_third_party_requests_switch);
128 ImageView blockAllThirdPartyRequestsImageView = domainSettingsView.findViewById(R.id.block_all_third_party_requests_imageview);
129 Spinner userAgentSpinner = domainSettingsView.findViewById(R.id.user_agent_spinner);
130 TextView userAgentTextView = domainSettingsView.findViewById(R.id.user_agent_textview);
131 EditText customUserAgentEditText = domainSettingsView.findViewById(R.id.custom_user_agent_edittext);
132 Spinner fontSizeSpinner = domainSettingsView.findViewById(R.id.font_size_spinner);
133 TextView fontSizeTextView = domainSettingsView.findViewById(R.id.font_size_textview);
134 ImageView swipeToRefreshImageView = domainSettingsView.findViewById(R.id.swipe_to_refresh_imageview);
135 Spinner swipeToRefreshSpinner = domainSettingsView.findViewById(R.id.swipe_to_refresh_spinner);
136 TextView swipeToRefreshTextView = domainSettingsView.findViewById(R.id.swipe_to_refresh_textview);
137 ImageView nightModeImageView = domainSettingsView.findViewById(R.id.night_mode_imageview);
138 Spinner nightModeSpinner = domainSettingsView.findViewById(R.id.night_mode_spinner);
139 TextView nightModeTextView = domainSettingsView.findViewById(R.id.night_mode_textview);
140 ImageView displayWebpageImagesImageView = domainSettingsView.findViewById(R.id.display_webpage_images_imageview);
141 Spinner displayWebpageImagesSpinner = domainSettingsView.findViewById(R.id.display_webpage_images_spinner);
142 TextView displayImagesTextView = domainSettingsView.findViewById(R.id.display_webpage_images_textview);
143 ImageView pinnedSslCertificateImageView = domainSettingsView.findViewById(R.id.pinned_ssl_certificate_imageview);
144 Switch pinnedSslCertificateSwitch = domainSettingsView.findViewById(R.id.pinned_ssl_certificate_switch);
145 CardView savedSslCardView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_cardview);
146 LinearLayout savedSslCertificateLinearLayout = domainSettingsView.findViewById(R.id.saved_ssl_certificate_linearlayout);
147 RadioButton savedSslCertificateRadioButton = domainSettingsView.findViewById(R.id.saved_ssl_certificate_radiobutton);
148 TextView savedSslIssuedToCNameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_to_cname);
149 TextView savedSslIssuedToONameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_to_oname);
150 TextView savedSslIssuedToUNameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_to_uname);
151 TextView savedSslIssuedByCNameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_by_cname);
152 TextView savedSslIssuedByONameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_by_oname);
153 TextView savedSslIssuedByUNameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_by_uname);
154 TextView savedSslStartDateTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_start_date);
155 TextView savedSslEndDateTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_end_date);
156 CardView currentSslCardView = domainSettingsView.findViewById(R.id.current_website_certificate_cardview);
157 LinearLayout currentWebsiteCertificateLinearLayout = domainSettingsView.findViewById(R.id.current_website_certificate_linearlayout);
158 RadioButton currentWebsiteCertificateRadioButton = domainSettingsView.findViewById(R.id.current_website_certificate_radiobutton);
159 TextView currentSslIssuedToCNameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_to_cname);
160 TextView currentSslIssuedToONameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_to_oname);
161 TextView currentSslIssuedToUNameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_to_uname);
162 TextView currentSslIssuedByCNameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_by_cname);
163 TextView currentSslIssuedByONameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_by_oname);
164 TextView currentSslIssuedByUNameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_by_uname);
165 TextView currentSslStartDateTextView = domainSettingsView.findViewById(R.id.current_website_certificate_start_date);
166 TextView currentSslEndDateTextView = domainSettingsView.findViewById(R.id.current_website_certificate_end_date);
167 TextView noCurrentWebsiteCertificateTextView = domainSettingsView.findViewById(R.id.no_current_website_certificate);
168 ImageView pinnedIpAddressesImageView = domainSettingsView.findViewById(R.id.pinned_ip_addresses_imageview);
169 Switch pinnedIpAddressesSwitch = domainSettingsView.findViewById(R.id.pinned_ip_addresses_switch);
170 CardView savedIpAddressesCardView = domainSettingsView.findViewById(R.id.saved_ip_addresses_cardview);
171 LinearLayout savedIpAddressesLinearLayout = domainSettingsView.findViewById(R.id.saved_ip_addresses_linearlayout);
172 RadioButton savedIpAddressesRadioButton = domainSettingsView.findViewById(R.id.saved_ip_addresses_radiobutton);
173 TextView savedIpAddressesTextView = domainSettingsView.findViewById(R.id.saved_ip_addresses_textview);
174 CardView currentIpAddressesCardView = domainSettingsView.findViewById(R.id.current_ip_addresses_cardview);
175 LinearLayout currentIpAddressesLinearLayout = domainSettingsView.findViewById(R.id.current_ip_addresses_linearlayout);
176 RadioButton currentIpAddressesRadioButton = domainSettingsView.findViewById(R.id.current_ip_addresses_radiobutton);
177 TextView currentIpAddressesTextView = domainSettingsView.findViewById(R.id.current_ip_addresses_textview);
179 // Setup the pinned labels.
180 String cNameLabel = getString(R.string.common_name) + " ";
181 String oNameLabel = getString(R.string.organization) + " ";
182 String uNameLabel = getString(R.string.organizational_unit) + " ";
183 String startDateLabel = getString(R.string.start_date) + " ";
184 String endDateLabel = getString(R.string.end_date) + " ";
186 // Initialize the database handler. The `0` specifies the database version, but that is ignored and set instead using a constant in `DomainsDatabaseHelper`.
187 DomainsDatabaseHelper domainsDatabaseHelper = new DomainsDatabaseHelper(context, null, null, 0);
189 // Get the database cursor for this ID and move it to the first row.
190 Cursor domainCursor = domainsDatabaseHelper.getCursorForId(databaseId);
191 domainCursor.moveToFirst();
193 // Save the cursor entries as variables.
194 String domainNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.DOMAIN_NAME));
195 int javaScriptEnabledInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_JAVASCRIPT));
196 int firstPartyCookiesEnabledInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FIRST_PARTY_COOKIES));
197 int thirdPartyCookiesEnabledInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_THIRD_PARTY_COOKIES));
198 int domStorageEnabledInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_DOM_STORAGE));
199 int formDataEnabledInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FORM_DATA)); // Form data can be remove once the minimum API >= 26.
200 int easyListEnabledInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_EASYLIST));
201 int easyPrivacyEnabledInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_EASYPRIVACY));
202 int fanboysAnnoyanceListInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FANBOYS_ANNOYANCE_LIST));
203 int fanboysSocialBlockingListInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FANBOYS_SOCIAL_BLOCKING_LIST));
204 int ultraPrivacyEnabledInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_ULTRAPRIVACY));
205 int blockAllThirdPartyRequestsInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.BLOCK_ALL_THIRD_PARTY_REQUESTS));
206 String currentUserAgentName = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.USER_AGENT));
207 int fontSizeInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.FONT_SIZE));
208 int swipeToRefreshInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.SWIPE_TO_REFRESH));
209 int nightModeInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.NIGHT_MODE));
210 int displayImagesInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.DISPLAY_IMAGES));
211 int pinnedSslCertificateInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.PINNED_SSL_CERTIFICATE));
212 String savedSslIssuedToCNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_TO_COMMON_NAME));
213 String savedSslIssuedToONameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_TO_ORGANIZATION));
214 String savedSslIssuedToUNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_TO_ORGANIZATIONAL_UNIT));
215 String savedSslIssuedByCNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_BY_COMMON_NAME));
216 String savedSslIssuedByONameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_BY_ORGANIZATION));
217 String savedSslIssuedByUNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_BY_ORGANIZATIONAL_UNIT));
218 int pinnedIpAddressesInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.PINNED_IP_ADDRESSES));
219 String savedIpAddresses = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.IP_ADDRESSES));
221 // Initialize the saved SSL certificate date variables.
222 Date savedSslStartDate = null;
223 Date savedSslEndDate = null;
225 // Only get the saved SSL certificate dates from the cursor if they are not set to `0`.
226 if (domainCursor.getLong(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_START_DATE)) != 0) {
227 savedSslStartDate = new Date(domainCursor.getLong(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_START_DATE)));
230 if (domainCursor.getLong(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_END_DATE)) != 0) {
231 savedSslEndDate = new Date(domainCursor.getLong(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_END_DATE)));
234 // Create array adapters for the spinners.
235 ArrayAdapter<CharSequence> translatedUserAgentArrayAdapter = ArrayAdapter.createFromResource(context, R.array.translated_domain_settings_user_agent_names, R.layout.spinner_item);
236 ArrayAdapter<CharSequence> fontSizeArrayAdapter = ArrayAdapter.createFromResource(context, R.array.domain_settings_font_size_entries, R.layout.spinner_item);
237 ArrayAdapter<CharSequence> fontSizeEntryValuesArrayAdapter = ArrayAdapter.createFromResource(context, R.array.domain_settings_font_size_entry_values, R.layout.spinner_item);
238 ArrayAdapter<CharSequence> swipeToRefreshArrayAdapter = ArrayAdapter.createFromResource(context, R.array.swipe_to_refresh_array, R.layout.spinner_item);
239 ArrayAdapter<CharSequence> nightModeArrayAdapter = ArrayAdapter.createFromResource(context, R.array.night_mode_array, R.layout.spinner_item);
240 ArrayAdapter<CharSequence> displayImagesArrayAdapter = ArrayAdapter.createFromResource(context, R.array.display_webpage_images_array, R.layout.spinner_item);
242 // Set the drop down view resource on the spinners.
243 translatedUserAgentArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items);
244 fontSizeArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items);
245 swipeToRefreshArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items);
246 nightModeArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items);
247 displayImagesArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items);
249 // Set the array adapters for the spinners.
250 userAgentSpinner.setAdapter(translatedUserAgentArrayAdapter);
251 fontSizeSpinner.setAdapter(fontSizeArrayAdapter);
252 swipeToRefreshSpinner.setAdapter(swipeToRefreshArrayAdapter);
253 nightModeSpinner.setAdapter(nightModeArrayAdapter);
254 displayWebpageImagesSpinner.setAdapter(displayImagesArrayAdapter);
256 // Create a spannable string builder for each TextView that needs multiple colors of text.
257 SpannableStringBuilder savedSslIssuedToCNameStringBuilder = new SpannableStringBuilder(cNameLabel + savedSslIssuedToCNameString);
258 SpannableStringBuilder savedSslIssuedToONameStringBuilder = new SpannableStringBuilder(oNameLabel + savedSslIssuedToONameString);
259 SpannableStringBuilder savedSslIssuedToUNameStringBuilder = new SpannableStringBuilder(uNameLabel + savedSslIssuedToUNameString);
260 SpannableStringBuilder savedSslIssuedByCNameStringBuilder = new SpannableStringBuilder(cNameLabel + savedSslIssuedByCNameString);
261 SpannableStringBuilder savedSslIssuedByONameStringBuilder = new SpannableStringBuilder(oNameLabel + savedSslIssuedByONameString);
262 SpannableStringBuilder savedSslIssuedByUNameStringBuilder = new SpannableStringBuilder(uNameLabel + savedSslIssuedByUNameString);
264 // Initialize the spannable string builders for the saved SSL certificate dates.
265 SpannableStringBuilder savedSslStartDateStringBuilder;
266 SpannableStringBuilder savedSslEndDateStringBuilder;
268 // Leave the SSL certificate dates empty if they are `null`.
269 if (savedSslStartDate == null) {
270 savedSslStartDateStringBuilder = new SpannableStringBuilder(startDateLabel);
272 savedSslStartDateStringBuilder = new SpannableStringBuilder(startDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(savedSslStartDate));
275 if (savedSslEndDate == null) {
276 savedSslEndDateStringBuilder = new SpannableStringBuilder(endDateLabel);
278 savedSslEndDateStringBuilder = new SpannableStringBuilder(endDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(savedSslEndDate));
281 // Create a red foreground color span. The deprecated `resources.getColor` must be used until the minimum API >= 23.
282 final ForegroundColorSpan redColorSpan = new ForegroundColorSpan(resources.getColor(R.color.red_a700));
284 // Create a blue foreground color span.
285 final ForegroundColorSpan blueColorSpan;
287 // Set the blue color span according to the theme. The deprecated `resources.getColor` must be used until the minimum API >= 23.
289 blueColorSpan = new ForegroundColorSpan(resources.getColor(R.color.blue_400));
291 blueColorSpan = new ForegroundColorSpan(resources.getColor(R.color.blue_700));
294 // Set the domain name from the the database cursor.
295 domainNameEditText.setText(domainNameString);
297 // Update the certificates' `Common Name` color when the domain name text changes.
298 domainNameEditText.addTextChangedListener(new TextWatcher() {
300 public void beforeTextChanged(CharSequence s, int start, int count, int after) {
305 public void onTextChanged(CharSequence s, int start, int before, int count) {
310 public void afterTextChanged(Editable s) {
311 // Get the new domain name.
312 String newDomainName = domainNameEditText.getText().toString();
314 // Check the saved SSL certificate against the new domain name.
315 boolean savedSslMatchesNewDomainName = checkDomainNameAgainstCertificate(newDomainName, savedSslIssuedToCNameString);
317 // Create a `SpannableStringBuilder` for the saved certificate `Common Name`.
318 SpannableStringBuilder savedSslCNameStringBuilder = new SpannableStringBuilder(cNameLabel + savedSslIssuedToCNameString);
320 // Format the saved certificate `Common Name` color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
321 if (savedSslMatchesNewDomainName) {
322 savedSslCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), savedSslCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
324 savedSslCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), savedSslCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
327 // Update the saved SSL issued to CName text view.
328 savedSslIssuedToCNameTextView.setText(savedSslCNameStringBuilder);
330 // Update the current website certificate if it exists.
331 if (DomainsActivity.sslIssuedToCName != null) {
332 // Check the current website certificate against the new domain name.
333 boolean currentSslMatchesNewDomainName = checkDomainNameAgainstCertificate(newDomainName, DomainsActivity.sslIssuedToCName);
335 // Create a `SpannableStringBuilder` for the current website certificate `Common Name`.
336 SpannableStringBuilder currentSslCNameStringBuilder = new SpannableStringBuilder(cNameLabel + DomainsActivity.sslIssuedToCName);
338 // Format the current certificate `Common Name` color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
339 if (currentSslMatchesNewDomainName) {
340 currentSslCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), currentSslCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
342 currentSslCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), currentSslCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
345 // Update the current SSL issued to CName text view.
346 currentSslIssuedToCNameTextView.setText(currentSslCNameStringBuilder);
351 // Create a boolean to track if night mode is enabled.
352 boolean nightModeEnabled = (nightModeInt == DomainsDatabaseHelper.NIGHT_MODE_ENABLED) || ((nightModeInt == DomainsDatabaseHelper.NIGHT_MODE_SYSTEM_DEFAULT) && defaultNightMode);
354 // Disable the JavaScript switch if night mode is enabled.
355 if (nightModeEnabled) {
356 javaScriptEnabledSwitch.setEnabled(false);
358 javaScriptEnabledSwitch.setEnabled(true);
361 // Set the JavaScript icon.
362 if ((javaScriptEnabledInt == 1) || nightModeEnabled) {
363 javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.javascript_enabled));
365 javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.privacy_mode));
368 // Set the JavaScript switch status.
369 if (javaScriptEnabledInt == 1) { // JavaScript is enabled.
370 javaScriptEnabledSwitch.setChecked(true);
371 } else { // JavaScript is disabled.
372 javaScriptEnabledSwitch.setChecked(false);
375 // 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.
376 if (firstPartyCookiesEnabledInt == 1) { // First-party cookies are enabled.
377 firstPartyCookiesEnabledSwitch.setChecked(true);
378 firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_enabled));
379 } else { // First-party cookies are disabled.
380 firstPartyCookiesEnabledSwitch.setChecked(false);
382 // Set the icon according to the theme.
384 firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_dark));
386 firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_light));
390 // Only display third-party cookies if SDK_INT >= 21.
391 if (Build.VERSION.SDK_INT >= 21) { // Third-party cookies can be configured for API >= 21.
392 // Only enable third-party-cookies if first-party cookies are enabled.
393 if (firstPartyCookiesEnabledInt == 1) { // First-party cookies are enabled.
394 // 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.
395 if (thirdPartyCookiesEnabledInt == 1) { // Both first-party and third-party cookies are enabled.
396 thirdPartyCookiesEnabledSwitch.setChecked(true);
397 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_warning));
398 } else { // First party cookies are enabled but third-party cookies are disabled.
399 thirdPartyCookiesEnabledSwitch.setChecked(false);
401 // Set the icon according to the theme.
403 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_dark));
405 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_light));
408 } else { // First-party cookies are disabled.
409 // Set the status of third-party cookies.
410 if (thirdPartyCookiesEnabledInt == 1) {
411 thirdPartyCookiesEnabledSwitch.setChecked(true);
413 thirdPartyCookiesEnabledSwitch.setChecked(false);
416 // Disable the third-party cookies switch.
417 thirdPartyCookiesEnabledSwitch.setEnabled(false);
419 // Set the icon according to the theme.
421 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_ghosted_dark));
423 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_ghosted_light));
426 } else { // Third-party cookies cannot be configured for API <= 21.
427 // Hide the LinearLayout for third-party cookies.
428 thirdPartyCookiesLinearLayout.setVisibility(View.GONE);
431 // Only enable DOM storage if JavaScript is enabled.
432 if ((javaScriptEnabledInt == 1) || nightModeEnabled) { // JavaScript is enabled.
433 // Enable the DOM storage `Switch`.
434 domStorageEnabledSwitch.setEnabled(true);
436 // Set the DOM storage status. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
437 if (domStorageEnabledInt == 1) { // Both JavaScript and DOM storage are enabled.
438 domStorageEnabledSwitch.setChecked(true);
439 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_enabled));
440 } else { // JavaScript is enabled but DOM storage is disabled.
441 // Set the DOM storage switch to off.
442 domStorageEnabledSwitch.setChecked(false);
444 // Set the icon according to the theme.
446 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_dark));
448 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_light));
451 } else { // JavaScript is disabled.
452 // Disable the DOM storage `Switch`.
453 domStorageEnabledSwitch.setEnabled(false);
455 // Set the checked status of DOM storage.
456 if (domStorageEnabledInt == 1) { // DOM storage is enabled but JavaScript is disabled.
457 domStorageEnabledSwitch.setChecked(true);
458 } else { // Both JavaScript and DOM storage are disabled.
459 domStorageEnabledSwitch.setChecked(false);
462 // Set the icon according to the theme.
464 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_dark));
466 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_light));
470 // 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.
471 if (Build.VERSION.SDK_INT >= 26) { // Form data no longer applies to newer versions of Android.
472 // Hide the form data switch.
473 formDataEnabledSwitch.setVisibility(View.GONE);
474 } else { // Form data should be displayed because this is an older version of Android.
475 if (formDataEnabledInt == 1) { // Form data is on.
476 formDataEnabledSwitch.setChecked(true);
477 formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_enabled));
478 } else { // Form data is off.
479 // Turn the form data switch to off.
480 formDataEnabledSwitch.setChecked(false);
482 // Set the icon according to the theme.
484 formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_disabled_dark));
486 formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_disabled_light));
491 // Set the EasyList status. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
492 if (easyListEnabledInt == 1) { // EasyList is on.
493 // Turn the switch on.
494 easyListSwitch.setChecked(true);
496 // Set the icon according to the theme.
498 easyListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_enabled_dark));
500 easyListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_enabled_light));
502 } else { // EasyList is off.
503 // Turn the switch off.
504 easyListSwitch.setChecked(false);
506 // Set the icon according to the theme.
508 easyListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_disabled_dark));
510 easyListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_disabled_light));
514 // Set the EasyPrivacy status. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
515 if (easyPrivacyEnabledInt == 1) { // EasyPrivacy is on.
516 // Turn the switch on.
517 easyPrivacySwitch.setChecked(true);
519 // Set the icon according to the theme.
521 easyPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_enabled_dark));
523 easyPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_enabled_light));
525 } else { // EasyPrivacy is off.
526 // Turn the switch off.
527 easyPrivacySwitch.setChecked(false);
529 // Set the icon according to the theme.
531 easyPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_disabled_dark));
533 easyPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_disabled_light));
537 // 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.
538 if (fanboysAnnoyanceListInt == 1) { // Fanboy's Annoyance List is on.
539 // Turn the switch on.
540 fanboysAnnoyanceListSwitch.setChecked(true);
542 // Set the icon according to the theme.
544 fanboysAnnoyanceListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_dark));
546 fanboysAnnoyanceListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_light));
548 } else { // Fanboy's Annoyance List is off.
549 // Turn the switch off.
550 fanboysAnnoyanceListSwitch.setChecked(false);
552 // Set the icon according to the theme.
554 fanboysAnnoyanceListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_dark));
556 fanboysAnnoyanceListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_light));
560 // Only enable Fanboy's Social Blocking List if Fanboy's Annoyance List is off.
561 if (fanboysAnnoyanceListInt == 0) { // Fanboy's Annoyance List is on.
562 // 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.
563 if (fanboysSocialBlockingListInt == 1) { // Fanboy's Social Blocking List is on.
564 // Enable the switch and turn it on.
565 fanboysSocialBlockingListSwitch.setEnabled(true);
566 fanboysSocialBlockingListSwitch.setChecked(true);
568 // Set the icon according to the theme.
570 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_dark));
572 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_light));
574 } else { // Fanboy's Social Blocking List is off.
575 // Enable the switch but turn it off.
576 fanboysSocialBlockingListSwitch.setEnabled(true);
577 fanboysSocialBlockingListSwitch.setChecked(false);
579 // Set the icon according to the theme.
581 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_dark));
583 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_light));
586 } else { // Fanboy's Annoyance List is on.
587 // 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.
588 if (fanboysSocialBlockingListInt == 1) { // Fanboy's Social Blocking List is on.
589 // Disable the switch but turn it on.
590 fanboysSocialBlockingListSwitch.setEnabled(false);
591 fanboysSocialBlockingListSwitch.setChecked(true);
592 } else { // Fanboy's Social Blocking List is off.
593 // Disable the switch and turn it off.
594 fanboysSocialBlockingListSwitch.setEnabled(false);
595 fanboysSocialBlockingListSwitch.setChecked(false);
598 // Set the icon according to the theme.
600 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_ghosted_dark));
602 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_ghosted_light));
606 // Set the UltraPrivacy status. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
607 if (ultraPrivacyEnabledInt == 1) { // UltraPrivacy is on.
608 // Turn the switch on.
609 ultraPrivacySwitch.setChecked(true);
611 // Set the icon according to the theme.
613 ultraPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_enabled_dark));
615 ultraPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_enabled_light));
617 } else { // EasyPrivacy is off.
618 // Turn the switch off.
619 ultraPrivacySwitch.setChecked(false);
621 // Set the icon according to the theme.
623 ultraPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_disabled_dark));
625 ultraPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_disabled_light));
629 // 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.
630 if (blockAllThirdPartyRequestsInt == 1) { // Blocking all third-party requests is on.
631 // Turn the switch on.
632 blockAllThirdPartyRequestsSwitch.setChecked(true);
634 // Set the icon according to the theme.
636 blockAllThirdPartyRequestsImageView.setImageDrawable(resources.getDrawable(R.drawable.block_all_third_party_requests_enabled_dark));
638 blockAllThirdPartyRequestsImageView.setImageDrawable(resources.getDrawable(R.drawable.block_all_third_party_requests_enabled_light));
640 } else { // Blocking all third-party requests is off.
641 // Turn the switch off.
642 blockAllThirdPartyRequestsSwitch.setChecked(false);
644 // Set the icon according to the theme.
646 blockAllThirdPartyRequestsImageView.setImageDrawable(resources.getDrawable(R.drawable.block_all_third_party_requests_disabled_dark));
648 blockAllThirdPartyRequestsImageView.setImageDrawable(resources.getDrawable(R.drawable.block_all_third_party_requests_disabled_light));
652 // Inflated a WebView to get the default user agent.
653 // `@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.
654 @SuppressLint("InflateParams") View bareWebViewLayout = inflater.inflate(R.layout.bare_webview, null, false);
655 WebView bareWebView = bareWebViewLayout.findViewById(R.id.bare_webview);
656 final String webViewDefaultUserAgentString = bareWebView.getSettings().getUserAgentString();
658 // Get a handle for the user agent array adapter. This array does not contain the `System default` entry.
659 ArrayAdapter<CharSequence> userAgentNamesArray = ArrayAdapter.createFromResource(context, R.array.user_agent_names, R.layout.spinner_item);
661 // Get the positions of the user agent and the default user agent.
662 int userAgentArrayPosition = userAgentNamesArray.getPosition(currentUserAgentName);
663 int defaultUserAgentArrayPosition = userAgentNamesArray.getPosition(defaultUserAgentName);
665 // Get a handle for the user agent data array. This array does not contain the `System default` entry.
666 String[] userAgentDataArray = resources.getStringArray(R.array.user_agent_data);
668 // Set the user agent text.
669 if (currentUserAgentName.equals(getString(R.string.system_default_user_agent))) { // Use the system default user agent.
670 // Set the user agent according to the system default.
671 switch (defaultUserAgentArrayPosition) {
672 case MainWebViewActivity.UNRECOGNIZED_USER_AGENT: // The default user agent name is not on the canonical list.
673 // This is probably because it was set in an older version of Privacy Browser before the switch to persistent user agent names.
674 userAgentTextView.setText(defaultUserAgentName);
677 case MainWebViewActivity.SETTINGS_WEBVIEW_DEFAULT_USER_AGENT:
678 // Display the `WebView` default user agent.
679 userAgentTextView.setText(webViewDefaultUserAgentString);
682 case MainWebViewActivity.SETTINGS_CUSTOM_USER_AGENT:
683 // Display the custom user agent.
684 userAgentTextView.setText(defaultCustomUserAgentString);
688 // Get the user agent string from the user agent data array.
689 userAgentTextView.setText(userAgentDataArray[defaultUserAgentArrayPosition]);
691 } else if (userAgentArrayPosition == MainWebViewActivity.UNRECOGNIZED_USER_AGENT) { // A custom user agent is stored in the current user agent name.
692 // Set the user agent spinner to `Custom user agent`.
693 userAgentSpinner.setSelection(MainWebViewActivity.DOMAINS_CUSTOM_USER_AGENT);
695 // Hide the user agent TextView.
696 userAgentTextView.setVisibility(View.GONE);
698 // Show the custom user agent EditText and set the current user agent name as the text.
699 customUserAgentEditText.setVisibility(View.VISIBLE);
700 customUserAgentEditText.setText(currentUserAgentName);
701 } else { // The user agent name contains one of the canonical user agents.
702 // 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.
703 userAgentSpinner.setSelection(userAgentArrayPosition + 1);
705 // Show the user agent TextView.
706 userAgentTextView.setVisibility(View.VISIBLE);
708 // Hide the custom user agent EditText.
709 customUserAgentEditText.setVisibility(View.GONE);
711 // Set the user agent text.
712 if (userAgentArrayPosition == MainWebViewActivity.DOMAINS_WEBVIEW_DEFAULT_USER_AGENT) { // The WebView default user agent is selected.
713 // Display the WebView default user agent.
714 userAgentTextView.setText(webViewDefaultUserAgentString);
715 } else { // A user agent besides the default is selected.
716 // 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.
717 userAgentTextView.setText(userAgentDataArray[userAgentArrayPosition + 1]);
721 // Open the user agent spinner when the TextView is clicked.
722 userAgentTextView.setOnClickListener((View v) -> {
723 // Open the user agent spinner.
724 userAgentSpinner.performClick();
727 // Set the selected font size.
728 int fontSizeArrayPosition = fontSizeEntryValuesArrayAdapter.getPosition(String.valueOf(fontSizeInt));
729 fontSizeSpinner.setSelection(fontSizeArrayPosition);
731 // Set the default font size text.
732 int defaultFontSizeArrayPosition = fontSizeEntryValuesArrayAdapter.getPosition(defaultFontSizeString);
733 fontSizeTextView.setText(fontSizeArrayAdapter.getItem(defaultFontSizeArrayPosition));
735 // Set the display options for the font size TextView.
736 if (fontSizeArrayPosition == 0) { // System default font size is selected. Display `fontSizeTextView`.
737 fontSizeTextView.setVisibility(View.VISIBLE);
738 } else { // A custom font size is specified. Hide `fontSizeTextView`.
739 fontSizeTextView.setVisibility(View.GONE);
742 // Open the font size spinner when the TextView is clicked.
743 fontSizeTextView.setOnClickListener((View v) -> {
744 // Open the user agent spinner.
745 fontSizeSpinner.performClick();
748 // Display the swipe to refresh selection in the spinner.
749 swipeToRefreshSpinner.setSelection(swipeToRefreshInt);
751 // Set the swipe to refresh text.
752 if (defaultSwipeToRefresh) {
753 swipeToRefreshTextView.setText(swipeToRefreshArrayAdapter.getItem(DomainsDatabaseHelper.SWIPE_TO_REFRESH_ENABLED));
755 swipeToRefreshTextView.setText(swipeToRefreshArrayAdapter.getItem(DomainsDatabaseHelper.SWIPE_TO_REFRESH_DISABLED));
758 // 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.
759 switch (swipeToRefreshInt) {
760 case DomainsDatabaseHelper.SWIPE_TO_REFRESH_SYSTEM_DEFAULT:
761 if (defaultSwipeToRefresh) { // Swipe to refresh is enabled by default.
762 // Set the icon according to the theme.
764 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_enabled_dark));
766 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_enabled_light));
768 } else { // Swipe to refresh is disabled by default
769 // Set the icon according to the theme.
771 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_disabled_dark));
773 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_disabled_light));
777 // Show the swipe to refresh TextView.
778 swipeToRefreshTextView.setVisibility(View.VISIBLE);
781 case DomainsDatabaseHelper.SWIPE_TO_REFRESH_ENABLED:
782 // Set the icon according to the theme.
784 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_enabled_dark));
786 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_enabled_light));
789 // Hide the swipe to refresh TextView.`
790 swipeToRefreshTextView.setVisibility(View.GONE);
793 case DomainsDatabaseHelper.SWIPE_TO_REFRESH_DISABLED:
794 // Set the icon according to the theme.
796 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_disabled_dark));
798 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_disabled_light));
801 // Hide the swipe to refresh TextView.
802 swipeToRefreshTextView.setVisibility(View.GONE);
805 // Open the swipe to refresh spinner when the TextView is clicked.
806 swipeToRefreshTextView.setOnClickListener((View v) -> {
807 // Open the swipe to refresh spinner.
808 swipeToRefreshSpinner.performClick();
811 // Display the night mode in the spinner.
812 nightModeSpinner.setSelection(nightModeInt);
814 // Set the default night mode text.
815 if (defaultNightMode) {
816 nightModeTextView.setText(nightModeArrayAdapter.getItem(DomainsDatabaseHelper.NIGHT_MODE_ENABLED));
818 nightModeTextView.setText(nightModeArrayAdapter.getItem(DomainsDatabaseHelper.NIGHT_MODE_DISABLED));
821 // 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.
822 switch (nightModeInt) {
823 case DomainsDatabaseHelper.NIGHT_MODE_SYSTEM_DEFAULT:
824 if (defaultNightMode) { // Night mode enabled by default.
825 // Set the icon according to the theme.
827 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_dark));
829 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_light));
831 } else { // Night mode disabled by default.
832 // Set the icon according to the theme.
834 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_dark));
836 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_light));
840 // Show night mode TextView.
841 nightModeTextView.setVisibility(View.VISIBLE);
844 case DomainsDatabaseHelper.NIGHT_MODE_ENABLED:
845 // Set the icon according to the theme.
847 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_dark));
849 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_light));
852 // Hide the night mode TextView.
853 nightModeTextView.setVisibility(View.GONE);
856 case DomainsDatabaseHelper.NIGHT_MODE_DISABLED:
857 // Set the icon according to the theme.
859 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_dark));
861 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_light));
864 // Hide the night mode TextView.
865 nightModeTextView.setVisibility(View.GONE);
869 // Open the night mode spinner when the TextView is clicked.
870 nightModeTextView.setOnClickListener((View v) -> {
871 // Open the night mode spinner.
872 nightModeSpinner.performClick();
875 // Display the website images mode in the spinner.
876 displayWebpageImagesSpinner.setSelection(displayImagesInt);
878 // Set the default display images text.
879 if (defaultDisplayWebpageImages) {
880 displayImagesTextView.setText(displayImagesArrayAdapter.getItem(DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_ENABLED));
882 displayImagesTextView.setText(displayImagesArrayAdapter.getItem(DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_DISABLED));
885 // 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.
886 switch (displayImagesInt) {
887 case DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_SYSTEM_DEFAULT:
888 if (defaultDisplayWebpageImages) { // Display webpage images enabled by default.
889 // Set the icon according to the theme.
891 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_dark));
893 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_light));
895 } else { // Display webpage images disabled by default.
896 // Set the icon according to the theme.
898 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_dark));
900 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_light));
904 // Show the display images TextView.
905 displayImagesTextView.setVisibility(View.VISIBLE);
908 case DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_ENABLED:
909 // Set the icon according to the theme.
911 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_dark));
913 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_light));
916 // Hide the display images TextView.
917 displayImagesTextView.setVisibility(View.GONE);
920 case DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_DISABLED:
921 // Set the icon according to the theme.
923 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_dark));
925 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_light));
928 // Hide the display images TextView.
929 displayImagesTextView.setVisibility(View.GONE);
933 // Open the display images spinner when the TextView is clicked.
934 displayImagesTextView.setOnClickListener((View v) -> {
935 // Open the user agent spinner.
936 displayWebpageImagesSpinner.performClick();
939 // Set the pinned SSL certificate icon.
940 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.
942 pinnedSslCertificateSwitch.setChecked(true);
944 // Set the icon according to the theme.
946 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_dark));
948 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_light));
950 } else { // Pinned SSL certificate is disabled.
951 // Uncheck the switch.
952 pinnedSslCertificateSwitch.setChecked(false);
954 // Set the icon according to the theme.
956 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_dark));
958 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_light));
962 // Store the current date.
963 Date currentDate = Calendar.getInstance().getTime();
965 // Setup the string builders to display the general certificate information in blue. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
966 savedSslIssuedToONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), savedSslIssuedToONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
967 savedSslIssuedToUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), savedSslIssuedToUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
968 savedSslIssuedByCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), savedSslIssuedByCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
969 savedSslIssuedByONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), savedSslIssuedByONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
970 savedSslIssuedByUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), savedSslIssuedByUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
972 // Check the certificate Common Name against the domain name.
973 boolean savedSslCommonNameMatchesDomainName = checkDomainNameAgainstCertificate(domainNameString, savedSslIssuedToCNameString);
975 // Format the issued to Common Name color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
976 if (savedSslCommonNameMatchesDomainName) {
977 savedSslIssuedToCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), savedSslIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
979 savedSslIssuedToCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), savedSslIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
982 // Format the start date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
983 if ((savedSslStartDate != null) && savedSslStartDate.after(currentDate)) { // The certificate start date is in the future.
984 savedSslStartDateStringBuilder.setSpan(redColorSpan, startDateLabel.length(), savedSslStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
985 } else { // The certificate start date is in the past.
986 savedSslStartDateStringBuilder.setSpan(blueColorSpan, startDateLabel.length(), savedSslStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
989 // Format the end date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
990 if ((savedSslEndDate != null) && savedSslEndDate.before(currentDate)) { // The certificate end date is in the past.
991 savedSslEndDateStringBuilder.setSpan(redColorSpan, endDateLabel.length(), savedSslEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
992 } else { // The certificate end date is in the future.
993 savedSslEndDateStringBuilder.setSpan(blueColorSpan, endDateLabel.length(), savedSslEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
996 // Display the saved website SSL certificate strings.
997 savedSslIssuedToCNameTextView.setText(savedSslIssuedToCNameStringBuilder);
998 savedSslIssuedToONameTextView.setText(savedSslIssuedToONameStringBuilder);
999 savedSslIssuedToUNameTextView.setText(savedSslIssuedToUNameStringBuilder);
1000 savedSslIssuedByCNameTextView.setText(savedSslIssuedByCNameStringBuilder);
1001 savedSslIssuedByONameTextView.setText(savedSslIssuedByONameStringBuilder);
1002 savedSslIssuedByUNameTextView.setText(savedSslIssuedByUNameStringBuilder);
1003 savedSslStartDateTextView.setText(savedSslStartDateStringBuilder);
1004 savedSslEndDateTextView.setText(savedSslEndDateStringBuilder);
1006 // Populate the current website SSL certificate if there is one.
1007 if (DomainsActivity.sslIssuedToCName != null) {
1008 // Get dates from the raw long values.
1009 Date currentSslStartDate = new Date(DomainsActivity.sslStartDateLong);
1010 Date currentSslEndDate = new Date(DomainsActivity.sslEndDateLong);
1012 // Create a spannable string builder for each text view that needs multiple colors of text.
1013 SpannableStringBuilder currentSslIssuedToCNameStringBuilder = new SpannableStringBuilder(cNameLabel + DomainsActivity.sslIssuedToCName);
1014 SpannableStringBuilder currentSslIssuedToONameStringBuilder = new SpannableStringBuilder(oNameLabel + DomainsActivity.sslIssuedToOName);
1015 SpannableStringBuilder currentSslIssuedToUNameStringBuilder = new SpannableStringBuilder(uNameLabel + DomainsActivity.sslIssuedToUName);
1016 SpannableStringBuilder currentSslIssuedByCNameStringBuilder = new SpannableStringBuilder(cNameLabel + DomainsActivity.sslIssuedByCName);
1017 SpannableStringBuilder currentSslIssuedByONameStringBuilder = new SpannableStringBuilder(oNameLabel + DomainsActivity.sslIssuedByOName);
1018 SpannableStringBuilder currentSslIssuedByUNameStringBuilder = new SpannableStringBuilder(uNameLabel + DomainsActivity.sslIssuedByUName);
1019 SpannableStringBuilder currentSslStartDateStringBuilder = new SpannableStringBuilder(startDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG)
1020 .format(currentSslStartDate));
1021 SpannableStringBuilder currentSslEndDateStringBuilder = new SpannableStringBuilder(endDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG)
1022 .format(currentSslEndDate));
1024 // Setup the string builders to display the general certificate information in blue. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
1025 currentSslIssuedToONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), currentSslIssuedToONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1026 currentSslIssuedToUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), currentSslIssuedToUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1027 currentSslIssuedByCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), currentSslIssuedByCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1028 currentSslIssuedByONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), currentSslIssuedByONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1029 currentSslIssuedByUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), currentSslIssuedByUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1031 // Check the certificate Common Name against the domain name.
1032 boolean currentSslCommonNameMatchesDomainName = checkDomainNameAgainstCertificate(domainNameString, DomainsActivity.sslIssuedToCName);
1034 // Format the issued to Common Name color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
1035 if (currentSslCommonNameMatchesDomainName) {
1036 currentSslIssuedToCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), currentSslIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1038 currentSslIssuedToCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), currentSslIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1041 // Format the start date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
1042 if (currentSslStartDate.after(currentDate)) { // The certificate start date is in the future.
1043 currentSslStartDateStringBuilder.setSpan(redColorSpan, startDateLabel.length(), currentSslStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1044 } else { // The certificate start date is in the past.
1045 currentSslStartDateStringBuilder.setSpan(blueColorSpan, startDateLabel.length(), currentSslStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1048 // Format the end date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
1049 if (currentSslEndDate.before(currentDate)) { // The certificate end date is in the past.
1050 currentSslEndDateStringBuilder.setSpan(redColorSpan, endDateLabel.length(), currentSslEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1051 } else { // The certificate end date is in the future.
1052 currentSslEndDateStringBuilder.setSpan(blueColorSpan, endDateLabel.length(), currentSslEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1055 // Display the current website SSL certificate strings.
1056 currentSslIssuedToCNameTextView.setText(currentSslIssuedToCNameStringBuilder);
1057 currentSslIssuedToONameTextView.setText(currentSslIssuedToONameStringBuilder);
1058 currentSslIssuedToUNameTextView.setText(currentSslIssuedToUNameStringBuilder);
1059 currentSslIssuedByCNameTextView.setText(currentSslIssuedByCNameStringBuilder);
1060 currentSslIssuedByONameTextView.setText(currentSslIssuedByONameStringBuilder);
1061 currentSslIssuedByUNameTextView.setText(currentSslIssuedByUNameStringBuilder);
1062 currentSslStartDateTextView.setText(currentSslStartDateStringBuilder);
1063 currentSslEndDateTextView.setText(currentSslEndDateStringBuilder);
1066 // Set the initial display status of the SSL certificates card views.
1067 if (pinnedSslCertificateSwitch.isChecked()) { // An SSL certificate is pinned.
1068 // Set the visibility of the saved SSL certificate.
1069 if (savedSslIssuedToCNameString == null) {
1070 savedSslCardView.setVisibility(View.GONE);
1072 savedSslCardView.setVisibility(View.VISIBLE);
1075 // Set the visibility of the current website SSL certificate.
1076 if (DomainsActivity.sslIssuedToCName == null) { // There is no current SSL certificate.
1077 // Hide the SSL certificate.
1078 currentSslCardView.setVisibility(View.GONE);
1080 // Show the instruction.
1081 noCurrentWebsiteCertificateTextView.setVisibility(View.VISIBLE);
1082 } else { // There is a current SSL certificate.
1083 // Show the SSL certificate.
1084 currentSslCardView.setVisibility(View.VISIBLE);
1086 // Hide the instruction.
1087 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
1090 // Set the status of the radio buttons and the card view backgrounds.
1091 if (savedSslCardView.getVisibility() == View.VISIBLE) { // The saved SSL certificate is displayed.
1092 // Check the saved SSL certificate radio button.
1093 savedSslCertificateRadioButton.setChecked(true);
1095 // Uncheck the current website SSL certificate radio button.
1096 currentWebsiteCertificateRadioButton.setChecked(false);
1098 // Darken the background of the current website SSL certificate linear layout according to the theme.
1100 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1102 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1104 } else if (currentSslCardView.getVisibility() == View.VISIBLE) { // The saved SSL certificate is hidden but the current website SSL certificate is visible.
1105 // Check the current website SSL certificate radio button.
1106 currentWebsiteCertificateRadioButton.setChecked(true);
1108 // Uncheck the saved SSL certificate radio button.
1109 savedSslCertificateRadioButton.setChecked(false);
1110 } else { // Neither SSL certificate is visible.
1111 // Uncheck both radio buttons.
1112 savedSslCertificateRadioButton.setChecked(false);
1113 currentWebsiteCertificateRadioButton.setChecked(false);
1115 } else { // An SSL certificate is not pinned.
1116 // Hide the SSl certificates and instructions.
1117 savedSslCardView.setVisibility(View.GONE);
1118 currentSslCardView.setVisibility(View.GONE);
1119 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
1121 // Uncheck the radio buttons.
1122 savedSslCertificateRadioButton.setChecked(false);
1123 currentWebsiteCertificateRadioButton.setChecked(false);
1126 // Set the pinned IP addresses icon.
1127 if (pinnedIpAddressesInt == 1) { // Pinned IP addresses is enabled. Once the minimum API >= 21 a selector can be sued as the tint mode instead of specifying different icons.
1128 // Check the switch.
1129 pinnedIpAddressesSwitch.setChecked(true);
1131 // Set the icon according to the theme.
1133 pinnedIpAddressesImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_dark));
1135 pinnedIpAddressesImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_light));
1137 } else { // Pinned IP Addresses is disabled.
1138 // Uncheck the switch.
1139 pinnedIpAddressesSwitch.setChecked(false);
1141 // Set the icon according to the theme.
1143 pinnedIpAddressesImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_dark));
1145 pinnedIpAddressesImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_light));
1149 // Populate the saved and current IP addresses.
1150 savedIpAddressesTextView.setText(savedIpAddresses);
1151 currentIpAddressesTextView.setText(DomainsActivity.currentIpAddresses);
1153 // Set the initial display status of the IP addresses card views.
1154 if (pinnedIpAddressesSwitch.isChecked()) { // IP addresses are pinned.
1155 // Set the visibility of the saved IP addresses.
1156 if (savedIpAddresses == null) { // There are no saved IP addresses.
1157 savedIpAddressesCardView.setVisibility(View.GONE);
1158 } else { // There are saved IP addresses.
1159 savedIpAddressesCardView.setVisibility(View.VISIBLE);
1162 // Set the visibility of the current IP addresses.
1163 currentIpAddressesCardView.setVisibility(View.VISIBLE);
1165 // Set the status of the radio buttons and the card view backgrounds.
1166 if (savedIpAddressesCardView.getVisibility() == View.VISIBLE) { // The saved IP addresses are displayed.
1167 // Check the saved IP addresses radio button.
1168 savedIpAddressesRadioButton.setChecked(true);
1170 // Uncheck the current IP addresses radio button.
1171 currentIpAddressesRadioButton.setChecked(false);
1173 // Darken the background of the current IP addresses linear layout according to the theme.
1175 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1177 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1179 } else { // The saved IP addresses are hidden.
1180 // Check the current IP addresses radio button.
1181 currentIpAddressesRadioButton.setChecked(true);
1183 // Uncheck the saved IP addresses radio button.
1184 savedIpAddressesRadioButton.setChecked(false);
1186 } else { // IP addresses are not pinned.
1187 // Hide the IP addresses card views.
1188 savedIpAddressesCardView.setVisibility(View.GONE);
1189 currentIpAddressesCardView.setVisibility(View.GONE);
1191 // Uncheck the radio buttons.
1192 savedIpAddressesRadioButton.setChecked(false);
1193 currentIpAddressesRadioButton.setChecked(false);
1197 // Set the JavaScript switch listener.
1198 javaScriptEnabledSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1199 if (isChecked) { // JavaScript is enabled.
1200 // Update the JavaScript icon.
1201 javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.javascript_enabled));
1203 // Enable the DOM storage `Switch`.
1204 domStorageEnabledSwitch.setEnabled(true);
1206 // Update the DOM storage icon.
1207 if (domStorageEnabledSwitch.isChecked()) { // DOM storage is enabled.
1208 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_enabled));
1209 } else { // DOM storage is disabled.
1210 // Set the icon according to the theme.
1212 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_dark));
1214 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_light));
1217 } else { // JavaScript is disabled.
1218 // Update the JavaScript icon.
1219 javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.privacy_mode));
1221 // Disable the DOM storage `Switch`.
1222 domStorageEnabledSwitch.setEnabled(false);
1224 // Set the DOM storage icon according to the theme.
1226 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_dark));
1228 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_light));
1233 // Set the first-party cookies switch listener.
1234 firstPartyCookiesEnabledSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1235 if (isChecked) { // First-party cookies are enabled.
1236 // Update the first-party cookies icon.
1237 firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_enabled));
1239 // Enable the third-party cookies switch.
1240 thirdPartyCookiesEnabledSwitch.setEnabled(true);
1242 // Update the third-party cookies icon.
1243 if (thirdPartyCookiesEnabledSwitch.isChecked()) { // Third-party cookies are enabled.
1244 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_warning));
1245 } else { // Third-party cookies are disabled.
1246 // Set the third-party cookies icon according to the theme.
1248 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_dark));
1250 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_light));
1253 } else { // First-party cookies are disabled.
1254 // Update the first-party cookies icon according to the theme.
1256 firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_dark));
1258 firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_light));
1261 // Disable the third-party cookies switch.
1262 thirdPartyCookiesEnabledSwitch.setEnabled(false);
1264 // Set the third-party cookies icon according to the theme.
1266 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_ghosted_dark));
1268 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_ghosted_light));
1273 // Set the third-party cookies switch listener.
1274 thirdPartyCookiesEnabledSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1277 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_warning));
1279 // Update the third-party cookies icon according to the theme.
1281 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_dark));
1283 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_light));
1288 // Set the DOM Storage switch listener.
1289 domStorageEnabledSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1292 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_enabled));
1294 // Set the icon according to the theme.
1296 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_dark));
1298 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_light));
1303 // Set the form data switch listener. It can be removed once the minimum API >= 26.
1304 if (Build.VERSION.SDK_INT < 26) {
1305 formDataEnabledSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1308 formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_enabled));
1310 // Set the icon according to the theme.
1312 formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_disabled_dark));
1314 formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_disabled_light));
1320 // Set the EasyList switch listener.
1321 easyListSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1323 if (isChecked) { // EasyList is on.
1324 // Set the icon according to the theme.
1326 easyListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_enabled_dark));
1328 easyListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_enabled_light));
1330 } else { // EasyList is off.
1331 // Set the icon according to the theme.
1333 easyListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_disabled_dark));
1335 easyListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_disabled_light));
1340 // Set the EasyPrivacy switch listener.
1341 easyPrivacySwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1343 if (isChecked) { // EasyPrivacy is on.
1344 // Set the icon according to the theme.
1346 easyPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_enabled_dark));
1348 easyPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_enabled_light));
1350 } else { // EasyPrivacy is off.
1351 // Set the icon according to the theme.
1353 easyPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_disabled_dark));
1355 easyPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_disabled_light));
1360 // Set the Fanboy's Annoyance List switch listener.
1361 fanboysAnnoyanceListSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1362 // Update the icon and Fanboy's Social Blocking List.
1363 if (isChecked) { // Fanboy's Annoyance List is on.
1364 // Set the icon according to the theme.
1366 fanboysAnnoyanceListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_dark));
1368 fanboysAnnoyanceListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_light));
1371 // Disable the Fanboy's Social Blocking List switch.
1372 fanboysSocialBlockingListSwitch.setEnabled(false);
1374 // Update the Fanboy's Social Blocking List icon according to the theme.
1376 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_ghosted_dark));
1378 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_ghosted_light));
1380 } else { // Fanboy's Annoyance List is off.
1381 // Set the icon according to the theme.
1383 fanboysAnnoyanceListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_dark));
1385 fanboysAnnoyanceListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_light));
1388 // Enable the Fanboy's Social Blocking List switch.
1389 fanboysSocialBlockingListSwitch.setEnabled(true);
1391 // Update the Fanboy's Social Blocking List icon.
1392 if (fanboysSocialBlockingListSwitch.isChecked()) { // Fanboy's Social Blocking List is on.
1393 // Update the icon according to the theme.
1395 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_dark));
1397 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_light));
1399 } else { // Fanboy's Social Blocking List is off.
1400 // Update the icon according to the theme.
1402 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_dark));
1404 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_light));
1411 // Set the Fanboy's Social Blocking List switch listener.
1412 fanboysSocialBlockingListSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1414 if (isChecked) { // Fanboy's Social Blocking List is on.
1415 // Set the icon according to the theme.
1417 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_dark));
1419 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_light));
1421 } else { // Fanboy's Social Blocking List is off.
1422 // Set the icon according to the theme.
1424 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_dark));
1426 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_light));
1431 // Set the UltraPrivacy switch listener.
1432 ultraPrivacySwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1434 if (isChecked) { // UltraPrivacy is on.
1435 // Set the icon according to the theme.
1437 ultraPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_enabled_dark));
1439 ultraPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_enabled_light));
1441 } else { // UltraPrivacy is off.
1442 // Set the icon according to the theme.
1444 ultraPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_disabled_dark));
1446 ultraPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_disabled_light));
1451 // Set the block all third-party requests switch listener.
1452 blockAllThirdPartyRequestsSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1454 if (isChecked) { // Blocking all third-party requests is on.
1455 // Set the icon according to the theme.
1457 blockAllThirdPartyRequestsImageView.setImageDrawable(resources.getDrawable(R.drawable.block_all_third_party_requests_enabled_dark));
1459 blockAllThirdPartyRequestsImageView.setImageDrawable(resources.getDrawable(R.drawable.block_all_third_party_requests_enabled_light));
1461 } else { // Blocking all third-party requests is off.
1462 // Set the icon according to the theme.
1464 blockAllThirdPartyRequestsImageView.setImageDrawable(resources.getDrawable(R.drawable.block_all_third_party_requests_disabled_dark));
1466 blockAllThirdPartyRequestsImageView.setImageDrawable(resources.getDrawable(R.drawable.block_all_third_party_requests_disabled_light));
1471 // Set the user agent spinner listener.
1472 userAgentSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1474 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1475 // Set the new user agent.
1477 case MainWebViewActivity.DOMAINS_SYSTEM_DEFAULT_USER_AGENT:
1478 // Show the user agent TextView.
1479 userAgentTextView.setVisibility(View.VISIBLE);
1481 // Hide the custom user agent EditText.
1482 customUserAgentEditText.setVisibility(View.GONE);
1484 // Set the user text.
1485 switch (defaultUserAgentArrayPosition) {
1486 case MainWebViewActivity.UNRECOGNIZED_USER_AGENT: // The default user agent name is not on the canonical list.
1487 // This is probably because it was set in an older version of Privacy Browser before the switch to persistent user agent names.
1488 userAgentTextView.setText(defaultUserAgentName);
1491 case MainWebViewActivity.SETTINGS_WEBVIEW_DEFAULT_USER_AGENT:
1492 // Display the `WebView` default user agent.
1493 userAgentTextView.setText(webViewDefaultUserAgentString);
1496 case MainWebViewActivity.SETTINGS_CUSTOM_USER_AGENT:
1497 // Display the custom user agent.
1498 userAgentTextView.setText(defaultCustomUserAgentString);
1502 // Get the user agent string from the user agent data array.
1503 userAgentTextView.setText(userAgentDataArray[defaultUserAgentArrayPosition]);
1507 case MainWebViewActivity.DOMAINS_WEBVIEW_DEFAULT_USER_AGENT:
1508 // Show the user agent TextView and set the text.
1509 userAgentTextView.setVisibility(View.VISIBLE);
1510 userAgentTextView.setText(webViewDefaultUserAgentString);
1512 // Hide the custom user agent EditTex.
1513 customUserAgentEditText.setVisibility(View.GONE);
1516 case MainWebViewActivity.DOMAINS_CUSTOM_USER_AGENT:
1517 // Hide the user agent TextView.
1518 userAgentTextView.setVisibility(View.GONE);
1520 // Show the custom user agent EditText and set the current user agent name as the text.
1521 customUserAgentEditText.setVisibility(View.VISIBLE);
1522 customUserAgentEditText.setText(currentUserAgentName);
1526 // 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.
1527 userAgentTextView.setVisibility(View.VISIBLE);
1528 userAgentTextView.setText(userAgentDataArray[position - 1]);
1530 // Hide `customUserAgentEditText`.
1531 customUserAgentEditText.setVisibility(View.GONE);
1536 public void onNothingSelected(AdapterView<?> parent) {
1541 // Set the font size spinner listener.
1542 fontSizeSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1544 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1545 // Update the display options for `fontSizeTextView`.
1546 if (position == 0) { // System default font size has been selected. Display `fontSizeTextView`.
1547 fontSizeTextView.setVisibility(View.VISIBLE);
1548 } else { // A custom font size has been selected. Hide `fontSizeTextView`.
1549 fontSizeTextView.setVisibility(View.GONE);
1554 public void onNothingSelected(AdapterView<?> parent) {
1559 // Set the swipe to refresh spinner listener.
1560 swipeToRefreshSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1562 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1563 // 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.
1565 case DomainsDatabaseHelper.SWIPE_TO_REFRESH_SYSTEM_DEFAULT:
1566 if (defaultSwipeToRefresh) { // Swipe to refresh enabled by default.
1567 // Set the icon according to the theme.
1569 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_enabled_dark));
1571 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_enabled_light));
1573 } else { // Swipe to refresh disabled by default.
1574 // Set the icon according to the theme.
1576 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_disabled_dark));
1578 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_disabled_light));
1582 // Show the swipe to refresh TextView.
1583 swipeToRefreshTextView.setVisibility(View.VISIBLE);
1586 case DomainsDatabaseHelper.SWIPE_TO_REFRESH_ENABLED:
1587 // Set the icon according to the theme.
1589 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_enabled_dark));
1591 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_enabled_light));
1594 // Hide the swipe to refresh TextView.
1595 swipeToRefreshTextView.setVisibility(View.GONE);
1598 case DomainsDatabaseHelper.SWIPE_TO_REFRESH_DISABLED:
1599 // Set the icon according to the theme.
1601 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_disabled_dark));
1603 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_disabled_light));
1606 // Hide the swipe to refresh TextView.
1607 swipeToRefreshTextView.setVisibility(View.GONE);
1612 public void onNothingSelected(AdapterView<?> parent) {
1617 // Set the night mode spinner listener.
1618 nightModeSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1620 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1621 // 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.
1623 case DomainsDatabaseHelper.NIGHT_MODE_SYSTEM_DEFAULT:
1624 if (defaultNightMode) { // Night mode enabled by default.
1625 // Set the icon according to the theme.
1627 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_dark));
1629 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_light));
1631 } else { // Night mode disabled by default.
1632 // Set the icon according to the theme.
1634 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_dark));
1636 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_light));
1640 // Show the night mode TextView.
1641 nightModeTextView.setVisibility(View.VISIBLE);
1644 case DomainsDatabaseHelper.NIGHT_MODE_ENABLED:
1645 // Set the icon according to the theme.
1647 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_dark));
1649 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_light));
1652 // Hide `nightModeTextView`.
1653 nightModeTextView.setVisibility(View.GONE);
1656 case DomainsDatabaseHelper.NIGHT_MODE_DISABLED:
1657 // Set the icon according to the theme.
1659 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_dark));
1661 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_light));
1664 // Hide `nightModeTextView`.
1665 nightModeTextView.setVisibility(View.GONE);
1669 // Create a `boolean` to store the current night mode setting.
1670 boolean currentNightModeEnabled = (position == DomainsDatabaseHelper.NIGHT_MODE_ENABLED) || ((position == DomainsDatabaseHelper.NIGHT_MODE_SYSTEM_DEFAULT) && defaultNightMode);
1672 // Disable the JavaScript `Switch` if night mode is enabled.
1673 if (currentNightModeEnabled) {
1674 javaScriptEnabledSwitch.setEnabled(false);
1676 javaScriptEnabledSwitch.setEnabled(true);
1679 // Update the JavaScript icon.
1680 if ((javaScriptEnabledInt == 1) || currentNightModeEnabled) {
1681 javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.javascript_enabled));
1683 javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.privacy_mode));
1686 // Update the DOM storage status.
1687 if ((javaScriptEnabledInt == 1) || currentNightModeEnabled) { // JavaScript is enabled.
1688 // Enable the DOM storage `Switch`.
1689 domStorageEnabledSwitch.setEnabled(true);
1691 // Set the DOM storage status. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
1692 if (domStorageEnabledInt == 1) { // Both JavaScript and DOM storage are enabled.
1693 domStorageEnabledSwitch.setChecked(true);
1694 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_enabled));
1695 } else { // JavaScript is enabled but DOM storage is disabled.
1696 // Set the DOM storage switch to off.
1697 domStorageEnabledSwitch.setChecked(false);
1699 // Set the icon according to the theme.
1701 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_dark));
1703 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_light));
1706 } else { // JavaScript is disabled.
1707 // Disable the DOM storage `Switch`.
1708 domStorageEnabledSwitch.setEnabled(false);
1710 // Set the checked status of DOM storage.
1711 if (domStorageEnabledInt == 1) { // DOM storage is enabled but JavaScript is disabled.
1712 domStorageEnabledSwitch.setChecked(true);
1713 } else { // Both JavaScript and DOM storage are disabled.
1714 domStorageEnabledSwitch.setChecked(false);
1717 // Set the icon according to the theme.
1719 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_dark));
1721 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_light));
1727 public void onNothingSelected(AdapterView<?> parent) {
1732 // Set the display webpage images spinner listener.
1733 displayWebpageImagesSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1735 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1736 // Update the icon and the visibility of `displayImagesTextView`.
1738 case DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_SYSTEM_DEFAULT:
1739 if (defaultDisplayWebpageImages) {
1740 // Set the icon according to the theme.
1742 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_dark));
1744 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_light));
1747 // Set the icon according to the theme.
1749 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_dark));
1751 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_light));
1755 // Show `displayImagesTextView`.
1756 displayImagesTextView.setVisibility(View.VISIBLE);
1759 case DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_ENABLED:
1760 // Set the icon according to the theme.
1762 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_dark));
1764 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_light));
1767 // Hide `displayImagesTextView`.
1768 displayImagesTextView.setVisibility(View.GONE);
1771 case DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_DISABLED:
1772 // Set the icon according to the theme.
1774 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_dark));
1776 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_light));
1779 // Hide `displayImagesTextView`.
1780 displayImagesTextView.setVisibility(View.GONE);
1786 public void onNothingSelected(AdapterView<?> parent) {
1791 // Set the pinned SSL certificate switch listener.
1792 pinnedSslCertificateSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1794 if (isChecked) { // SSL certificate pinning is enabled.
1795 // Set the icon according to the theme.
1797 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_dark));
1799 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_light));
1802 // Update the visibility of the saved SSL certificate.
1803 if (savedSslIssuedToCNameString == null) {
1804 savedSslCardView.setVisibility(View.GONE);
1806 savedSslCardView.setVisibility(View.VISIBLE);
1809 // Update the visibility of the current website SSL certificate.
1810 if (DomainsActivity.sslIssuedToCName == null) {
1811 // Hide the SSL certificate.
1812 currentSslCardView.setVisibility(View.GONE);
1814 // Show the instruction.
1815 noCurrentWebsiteCertificateTextView.setVisibility(View.VISIBLE);
1817 // Show the SSL certificate.
1818 currentSslCardView.setVisibility(View.VISIBLE);
1820 // Hide the instruction.
1821 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
1824 // Set the status of the radio buttons.
1825 if (savedSslCardView.getVisibility() == View.VISIBLE) { // The saved SSL certificate is displayed.
1826 // Check the saved SSL certificate radio button.
1827 savedSslCertificateRadioButton.setChecked(true);
1829 // Uncheck the current website SSL certificate radio button.
1830 currentWebsiteCertificateRadioButton.setChecked(false);
1832 // Set the background of the saved SSL certificate linear layout to be transparent.
1833 savedSslCertificateLinearLayout.setBackgroundResource(R.color.transparent);
1835 // Darken the background of the current website SSL certificate linear layout according to the theme.
1837 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1839 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1842 // Scroll to the current website SSL certificate card.
1843 savedSslCardView.getParent().requestChildFocus(savedSslCardView, savedSslCardView);
1844 } else if (currentSslCardView.getVisibility() == View.VISIBLE) { // The saved SSL certificate is hidden but the current website SSL certificate is visible.
1845 // Check the current website SSL certificate radio button.
1846 currentWebsiteCertificateRadioButton.setChecked(true);
1848 // Uncheck the saved SSL certificate radio button.
1849 savedSslCertificateRadioButton.setChecked(false);
1851 // Set the background of the current website SSL certificate linear layout to be transparent.
1852 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.transparent);
1854 // Darken the background of the saved SSL certificate linear layout according to the theme.
1856 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1858 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1861 // Scroll to the current website SSL certificate card.
1862 currentSslCardView.getParent().requestChildFocus(currentSslCardView, currentSslCardView);
1863 } else { // Neither SSL certificate is visible.
1864 // Uncheck both radio buttons.
1865 savedSslCertificateRadioButton.setChecked(false);
1866 currentWebsiteCertificateRadioButton.setChecked(false);
1868 // Scroll to the current website SSL certificate card.
1869 noCurrentWebsiteCertificateTextView.getParent().requestChildFocus(noCurrentWebsiteCertificateTextView, noCurrentWebsiteCertificateTextView);
1871 } else { // SSL certificate pinning is disabled.
1872 // Set the icon according to the theme.
1874 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_dark));
1876 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_light));
1879 // Hide the SSl certificates and instructions.
1880 savedSslCardView.setVisibility(View.GONE);
1881 currentSslCardView.setVisibility(View.GONE);
1882 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
1884 // Uncheck the radio buttons.
1885 savedSslCertificateRadioButton.setChecked(false);
1886 currentWebsiteCertificateRadioButton.setChecked(false);
1890 savedSslCardView.setOnClickListener((View view) -> {
1891 // Check the saved SSL certificate radio button.
1892 savedSslCertificateRadioButton.setChecked(true);
1894 // Uncheck the current website SSL certificate radio button.
1895 currentWebsiteCertificateRadioButton.setChecked(false);
1897 // Set the background of the saved SSL certificate linear layout to be transparent.
1898 savedSslCertificateLinearLayout.setBackgroundResource(R.color.transparent);
1900 // Darken the background of the current website SSL certificate linear layout according to the theme.
1902 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1904 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1908 savedSslCertificateRadioButton.setOnClickListener((View view) -> {
1909 // Check the saved SSL certificate radio button.
1910 savedSslCertificateRadioButton.setChecked(true);
1912 // Uncheck the current website SSL certificate radio button.
1913 currentWebsiteCertificateRadioButton.setChecked(false);
1915 // Set the background of the saved SSL certificate linear layout to be transparent.
1916 savedSslCertificateLinearLayout.setBackgroundResource(R.color.transparent);
1918 // Darken the background of the current website SSL certificate linear layout according to the theme.
1920 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1922 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1926 currentSslCardView.setOnClickListener((View view) -> {
1927 // Check the current website SSL certificate radio button.
1928 currentWebsiteCertificateRadioButton.setChecked(true);
1930 // Uncheck the saved SSL certificate radio button.
1931 savedSslCertificateRadioButton.setChecked(false);
1933 // Set the background of the current website SSL certificate linear layout to be transparent.
1934 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.transparent);
1936 // Darken the background of the saved SSL certificate linear layout according to the theme.
1938 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1940 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1944 currentWebsiteCertificateRadioButton.setOnClickListener((View view) -> {
1945 // Check the current website SSL certificate radio button.
1946 currentWebsiteCertificateRadioButton.setChecked(true);
1948 // Uncheck the saved SSL certificate radio button.
1949 savedSslCertificateRadioButton.setChecked(false);
1951 // Set the background of the current website SSL certificate linear layout to be transparent.
1952 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.transparent);
1954 // Darken the background of the saved SSL certificate linear layout according to the theme.
1956 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1958 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1962 // Set the pinned IP addresses switch listener.
1963 pinnedIpAddressesSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1965 if (isChecked) { // IP addresses pinning is enabled.
1966 // Set the icon according to the theme.
1968 pinnedIpAddressesImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_dark));
1970 pinnedIpAddressesImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_light));
1973 // Update the visibility of the saved IP addresses card view.
1974 if (savedIpAddresses == null) { // There are no saved IP addresses.
1975 savedIpAddressesCardView.setVisibility(View.GONE);
1976 } else { // There are saved IP addresses.
1977 savedIpAddressesCardView.setVisibility(View.VISIBLE);
1980 // Show the current IP addresses card view.
1981 currentIpAddressesCardView.setVisibility(View.VISIBLE);
1983 // Set the status of the radio buttons.
1984 if (savedIpAddressesCardView.getVisibility() == View.VISIBLE) { // The saved IP addresses are visible.
1985 // Check the saved IP addresses radio button.
1986 savedIpAddressesRadioButton.setChecked(true);
1988 // Uncheck the current IP addresses radio button.
1989 currentIpAddressesRadioButton.setChecked(false);
1991 // Set the background of the saved IP addresses linear layout to be transparent.
1992 savedSslCertificateLinearLayout.setBackgroundResource(R.color.transparent);
1994 // Darken the background of the current IP addresses linear layout according to the theme.
1996 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1998 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2000 } else { // The saved IP addresses are not visible.
2001 // Check the current IP addresses radio button.
2002 currentIpAddressesRadioButton.setChecked(true);
2004 // Uncheck the saved IP addresses radio button.
2005 savedIpAddressesRadioButton.setChecked(false);
2007 // Set the background of the current IP addresses linear layout to be transparent.
2008 currentIpAddressesLinearLayout.setBackgroundResource(R.color.transparent);
2010 // Darken the background of the saved IP addresses linear layout according to the theme.
2012 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2014 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2018 // Scroll to the bottom of the card views.
2019 currentIpAddressesCardView.getParent().requestChildFocus(currentIpAddressesCardView, currentIpAddressesCardView);
2020 } else { // IP addresses pinning is disabled.
2021 // Set the icon according to the theme.
2023 pinnedIpAddressesImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_dark));
2025 pinnedIpAddressesImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_light));
2028 // Hide the IP addresses card views.
2029 savedIpAddressesCardView.setVisibility(View.GONE);
2030 currentIpAddressesCardView.setVisibility(View.GONE);
2032 // Uncheck the radio buttons.
2033 savedIpAddressesRadioButton.setChecked(false);
2034 currentIpAddressesRadioButton.setChecked(false);
2038 savedIpAddressesCardView.setOnClickListener((View view) -> {
2039 // Check the saved IP addresses radio button.
2040 savedIpAddressesRadioButton.setChecked(true);
2042 // Uncheck the current website IP addresses radio button.
2043 currentIpAddressesRadioButton.setChecked(false);
2045 // Set the background of the saved IP addresses linear layout to be transparent.
2046 savedIpAddressesLinearLayout.setBackgroundResource(R.color.transparent);
2048 // Darken the background of the current IP addresses linear layout according to the theme.
2050 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2052 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2056 savedIpAddressesRadioButton.setOnClickListener((View view) -> {
2057 // Check the saved IP addresses radio button.
2058 savedIpAddressesRadioButton.setChecked(true);
2060 // Uncheck the current website IP addresses radio button.
2061 currentIpAddressesRadioButton.setChecked(false);
2063 // Set the background of the saved IP addresses linear layout to be transparent.
2064 savedIpAddressesLinearLayout.setBackgroundResource(R.color.transparent);
2066 // Darken the background of the current IP addresses linear layout according to the theme.
2068 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2070 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2074 currentIpAddressesCardView.setOnClickListener((View view) -> {
2075 // Check the current IP addresses radio button.
2076 currentIpAddressesRadioButton.setChecked(true);
2078 // Uncheck the saved IP addresses radio button.
2079 savedIpAddressesRadioButton.setChecked(false);
2081 // Set the background of the current IP addresses linear layout to be transparent.
2082 currentIpAddressesLinearLayout.setBackgroundResource(R.color.transparent);
2084 // Darken the background of the saved IP addresses linear layout according to the theme.
2086 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2088 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2092 currentIpAddressesRadioButton.setOnClickListener((View view) -> {
2093 // Check the current IP addresses radio button.
2094 currentIpAddressesRadioButton.setChecked(true);
2096 // Uncheck the saved IP addresses radio button.
2097 savedIpAddressesRadioButton.setChecked(false);
2099 // Set the background of the current IP addresses linear layout to be transparent.
2100 currentIpAddressesLinearLayout.setBackgroundResource(R.color.transparent);
2102 // Darken the background of the saved IP addresses linear layout according to the theme.
2104 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2106 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2110 return domainSettingsView;
2113 private boolean checkDomainNameAgainstCertificate(String domainName, String certificateCommonName) {
2114 // Initialize `domainNamesMatch`.
2115 boolean domainNamesMatch = false;
2117 // Check various wildcard permutations if `domainName` and `certificateCommonName` are not empty.
2118 // `noinspection ConstantCondition` removes Android Studio's incorrect lint warning that `domainName` can never be `null`.
2119 if ((domainName != null) && (certificateCommonName != null)) {
2120 // Check if the domains match.
2121 if (domainName.equals(certificateCommonName)) {
2122 domainNamesMatch = true;
2125 // If `domainName` starts with a wildcard, check the base domain against all the subdomains of `certificateCommonName`.
2126 if (!domainNamesMatch && domainName.startsWith("*.") && (domainName.length() > 2)) {
2127 // Remove the initial `*.`.
2128 String baseDomainName = domainName.substring(2);
2130 // Setup a copy of `certificateCommonName` to test subdomains.
2131 String certificateCommonNameSubdomain = certificateCommonName;
2133 // Check all the subdomains in `certificateCommonNameSubdomain` against `baseDomainName`.
2134 while (!domainNamesMatch && certificateCommonNameSubdomain.contains(".")) { // Stop checking if we know that `domainNamesMatch` is `true` or if we run out of `.`.
2135 // Test the `certificateCommonNameSubdomain` against `baseDomainName`.
2136 if (certificateCommonNameSubdomain.equals(baseDomainName)) {
2137 domainNamesMatch = true;
2140 // Strip out the lowest subdomain of `certificateCommonNameSubdomain`.
2142 certificateCommonNameSubdomain = certificateCommonNameSubdomain.substring(certificateCommonNameSubdomain.indexOf(".") + 1);
2143 } catch (IndexOutOfBoundsException e) { // `certificateCommonNameSubdomain` ends with `.`.
2144 certificateCommonNameSubdomain = "";
2149 // If `certificateCommonName` starts with a wildcard, check the base common name against all the subdomains of `domainName`.
2150 if (!domainNamesMatch && certificateCommonName.startsWith("*.") && (certificateCommonName.length() > 2)) {
2151 // Remove the initial `*.`.
2152 String baseCertificateCommonName = certificateCommonName.substring(2);
2154 // Setup a copy of `domainName` to test subdomains.
2155 String domainNameSubdomain = domainName;
2157 // Check all the subdomains in `domainNameSubdomain` against `baseCertificateCommonName`.
2158 while (!domainNamesMatch && domainNameSubdomain.contains(".") && (domainNameSubdomain.length() > 2)) {
2159 // Test the `domainNameSubdomain` against `baseCertificateCommonName`.
2160 if (domainNameSubdomain.equals(baseCertificateCommonName)) {
2161 domainNamesMatch = true;
2164 // Strip out the lowest subdomain of `domainNameSubdomain`.
2166 domainNameSubdomain = domainNameSubdomain.substring(domainNameSubdomain.indexOf(".") + 1);
2167 } catch (IndexOutOfBoundsException e) { // `domainNameSubdomain` ends with `.`.
2168 domainNameSubdomain = "";
2173 // If both names start with a wildcard, check if the root of one contains the root of the other.
2174 if (!domainNamesMatch && domainName.startsWith("*.") && (domainName.length() > 2) && certificateCommonName.startsWith("*.") && (certificateCommonName.length() > 2)) {
2175 // Remove the wildcards.
2176 String rootDomainName = domainName.substring(2);
2177 String rootCertificateCommonName = certificateCommonName.substring(2);
2179 // Check if one name ends with the contents of the other. If so, there will be overlap in the their wildcard subdomains.
2180 if (rootDomainName.endsWith(rootCertificateCommonName) || rootCertificateCommonName.endsWith(rootDomainName)) {
2181 domainNamesMatch = true;
2186 return domainNamesMatch;