2 * Copyright © 2017-2020 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.Configuration;
26 import android.content.res.Resources;
27 import android.database.Cursor;
28 import android.os.Build;
29 import android.os.Bundle;
30 import android.preference.PreferenceManager;
31 import android.text.Editable;
32 import android.text.SpannableStringBuilder;
33 import android.text.Spanned;
34 import android.text.TextWatcher;
35 import android.text.style.ForegroundColorSpan;
36 import android.view.LayoutInflater;
37 import android.view.View;
38 import android.view.ViewGroup;
39 import android.webkit.WebView;
40 import android.widget.AdapterView;
41 import android.widget.ArrayAdapter;
42 import android.widget.CompoundButton;
43 import android.widget.EditText;
44 import android.widget.ImageView;
45 import android.widget.LinearLayout;
46 import android.widget.RadioButton;
47 import android.widget.ScrollView;
48 import android.widget.Spinner;
49 import android.widget.TextView;
51 import androidx.annotation.NonNull;
52 import androidx.appcompat.widget.SwitchCompat;
53 import androidx.cardview.widget.CardView;
54 import androidx.core.content.res.ResourcesCompat;
55 import androidx.fragment.app.Fragment; // The AndroidX fragment must be used until minimum API >= 23. Otherwise `getContext()` does not work.
57 import com.stoutner.privacybrowser.R;
58 import com.stoutner.privacybrowser.activities.DomainsActivity;
59 import com.stoutner.privacybrowser.activities.MainWebViewActivity;
60 import com.stoutner.privacybrowser.helpers.DomainsDatabaseHelper;
62 import java.text.DateFormat;
63 import java.util.Calendar;
64 import java.util.Date;
66 public class DomainSettingsFragment extends Fragment {
67 // Initialize the public class constants. These are used by activities calling this fragment.
68 public static final String DATABASE_ID = "database_id";
69 public static final String SCROLL_Y = "scroll_y";
71 // Define the public variables. `databaseId` is public static so it can be accessed from `DomainsActivity`. It is also used in `onCreate()` and `onCreateView()`.
72 public static int databaseId;
74 // Define the class variables.
78 public void onCreate(Bundle savedInstanceState) {
79 // Run the default commands.
80 super.onCreate(savedInstanceState);
82 // Remove the lint warning that `getArguments` might be null.
83 assert getArguments() != null;
85 // Store the database id in `databaseId`.
86 databaseId = getArguments().getInt(DATABASE_ID);
87 scrollY = getArguments().getInt(SCROLL_Y);
90 // The deprecated `getDrawable()` must be used until the minimum API >= 21.
92 public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
93 // Inflate `domain_settings_fragment`. `false` does not attach it to the root `container`.
94 View domainSettingsView = inflater.inflate(R.layout.domain_settings_fragment, container, false);
96 // Get handles for the context and the resources.
97 Context context = getContext();
98 Resources resources = getResources();
100 // Remove the error below that the context might be null.
101 assert context != null;
103 // Get the current theme status.
104 int currentThemeStatus = getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
106 // Get a handle for the shared preference.
107 SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
109 // Store the default settings.
110 String defaultUserAgentName = sharedPreferences.getString("user_agent", getString(R.string.user_agent_default_value));
111 String defaultCustomUserAgentString = sharedPreferences.getString("custom_user_agent", getString(R.string.custom_user_agent_default_value));
112 String defaultFontSizeString = sharedPreferences.getString("font_size", getString(R.string.font_size_default_value));
113 boolean defaultSwipeToRefresh = sharedPreferences.getBoolean("swipe_to_refresh", true);
114 String defaultWebViewTheme = sharedPreferences.getString("webview_theme", getString(R.string.webview_theme_default_value));
115 boolean defaultWideViewport = sharedPreferences.getBoolean("wide_viewport", true);
116 boolean defaultDisplayWebpageImages = sharedPreferences.getBoolean("display_webpage_images", true);
118 // Get handles for the views.
119 ScrollView domainSettingsScrollView = domainSettingsView.findViewById(R.id.domain_settings_scrollview);
120 EditText domainNameEditText = domainSettingsView.findViewById(R.id.domain_settings_name_edittext);
121 ImageView javaScriptImageView = domainSettingsView.findViewById(R.id.javascript_imageview);
122 SwitchCompat javaScriptSwitch = domainSettingsView.findViewById(R.id.javascript_switch);
123 ImageView firstPartyCookiesImageView = domainSettingsView.findViewById(R.id.first_party_cookies_imageview);
124 SwitchCompat firstPartyCookiesSwitch = domainSettingsView.findViewById(R.id.first_party_cookies_switch);
125 LinearLayout thirdPartyCookiesLinearLayout = domainSettingsView.findViewById(R.id.third_party_cookies_linearlayout);
126 ImageView thirdPartyCookiesImageView = domainSettingsView.findViewById(R.id.third_party_cookies_imageview);
127 SwitchCompat thirdPartyCookiesSwitch = domainSettingsView.findViewById(R.id.third_party_cookies_switch);
128 ImageView domStorageImageView = domainSettingsView.findViewById(R.id.dom_storage_imageview);
129 SwitchCompat domStorageSwitch = domainSettingsView.findViewById(R.id.dom_storage_switch);
130 ImageView formDataImageView = domainSettingsView.findViewById(R.id.form_data_imageview); // The form data views can be remove once the minimum API >= 26.
131 SwitchCompat formDataSwitch = domainSettingsView.findViewById(R.id.form_data_switch); // The form data views can be remove once the minimum API >= 26.
132 ImageView easyListImageView = domainSettingsView.findViewById(R.id.easylist_imageview);
133 SwitchCompat easyListSwitch = domainSettingsView.findViewById(R.id.easylist_switch);
134 ImageView easyPrivacyImageView = domainSettingsView.findViewById(R.id.easyprivacy_imageview);
135 SwitchCompat easyPrivacySwitch = domainSettingsView.findViewById(R.id.easyprivacy_switch);
136 ImageView fanboysAnnoyanceListImageView = domainSettingsView.findViewById(R.id.fanboys_annoyance_list_imageview);
137 SwitchCompat fanboysAnnoyanceListSwitch = domainSettingsView.findViewById(R.id.fanboys_annoyance_list_switch);
138 ImageView fanboysSocialBlockingListImageView = domainSettingsView.findViewById(R.id.fanboys_social_blocking_list_imageview);
139 SwitchCompat fanboysSocialBlockingListSwitch = domainSettingsView.findViewById(R.id.fanboys_social_blocking_list_switch);
140 ImageView ultraListImageView = domainSettingsView.findViewById(R.id.ultralist_imageview);
141 SwitchCompat ultraListSwitch = domainSettingsView.findViewById(R.id.ultralist_switch);
142 ImageView ultraPrivacyImageView = domainSettingsView.findViewById(R.id.ultraprivacy_imageview);
143 SwitchCompat ultraPrivacySwitch = domainSettingsView.findViewById(R.id.ultraprivacy_switch);
144 ImageView blockAllThirdPartyRequestsImageView = domainSettingsView.findViewById(R.id.block_all_third_party_requests_imageview);
145 SwitchCompat blockAllThirdPartyRequestsSwitch = domainSettingsView.findViewById(R.id.block_all_third_party_requests_switch);
146 Spinner userAgentSpinner = domainSettingsView.findViewById(R.id.user_agent_spinner);
147 TextView userAgentTextView = domainSettingsView.findViewById(R.id.user_agent_textview);
148 EditText customUserAgentEditText = domainSettingsView.findViewById(R.id.custom_user_agent_edittext);
149 Spinner fontSizeSpinner = domainSettingsView.findViewById(R.id.font_size_spinner);
150 TextView defaultFontSizeTextView = domainSettingsView.findViewById(R.id.default_font_size_textview);
151 EditText customFontSizeEditText = domainSettingsView.findViewById(R.id.custom_font_size_edittext);
152 ImageView swipeToRefreshImageView = domainSettingsView.findViewById(R.id.swipe_to_refresh_imageview);
153 Spinner swipeToRefreshSpinner = domainSettingsView.findViewById(R.id.swipe_to_refresh_spinner);
154 TextView swipeToRefreshTextView = domainSettingsView.findViewById(R.id.swipe_to_refresh_textview);
155 ImageView webViewThemeImageView = domainSettingsView.findViewById(R.id.webview_theme_imageview);
156 Spinner webViewThemeSpinner = domainSettingsView.findViewById(R.id.webview_theme_spinner);
157 TextView webViewThemeTextView = domainSettingsView.findViewById(R.id.webview_theme_textview);
158 ImageView wideViewportImageView = domainSettingsView.findViewById(R.id.wide_viewport_imageview);
159 Spinner wideViewportSpinner = domainSettingsView.findViewById(R.id.wide_viewport_spinner);
160 TextView wideViewportTextView = domainSettingsView.findViewById(R.id.wide_viewport_textview);
161 ImageView displayWebpageImagesImageView = domainSettingsView.findViewById(R.id.display_webpage_images_imageview);
162 Spinner displayWebpageImagesSpinner = domainSettingsView.findViewById(R.id.display_webpage_images_spinner);
163 TextView displayImagesTextView = domainSettingsView.findViewById(R.id.display_webpage_images_textview);
164 ImageView pinnedSslCertificateImageView = domainSettingsView.findViewById(R.id.pinned_ssl_certificate_imageview);
165 SwitchCompat pinnedSslCertificateSwitch = domainSettingsView.findViewById(R.id.pinned_ssl_certificate_switch);
166 CardView savedSslCardView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_cardview);
167 LinearLayout savedSslCertificateLinearLayout = domainSettingsView.findViewById(R.id.saved_ssl_certificate_linearlayout);
168 RadioButton savedSslCertificateRadioButton = domainSettingsView.findViewById(R.id.saved_ssl_certificate_radiobutton);
169 TextView savedSslIssuedToCNameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_to_cname);
170 TextView savedSslIssuedToONameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_to_oname);
171 TextView savedSslIssuedToUNameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_to_uname);
172 TextView savedSslIssuedByCNameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_by_cname);
173 TextView savedSslIssuedByONameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_by_oname);
174 TextView savedSslIssuedByUNameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_by_uname);
175 TextView savedSslStartDateTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_start_date);
176 TextView savedSslEndDateTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_end_date);
177 CardView currentSslCardView = domainSettingsView.findViewById(R.id.current_website_certificate_cardview);
178 LinearLayout currentWebsiteCertificateLinearLayout = domainSettingsView.findViewById(R.id.current_website_certificate_linearlayout);
179 RadioButton currentWebsiteCertificateRadioButton = domainSettingsView.findViewById(R.id.current_website_certificate_radiobutton);
180 TextView currentSslIssuedToCNameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_to_cname);
181 TextView currentSslIssuedToONameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_to_oname);
182 TextView currentSslIssuedToUNameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_to_uname);
183 TextView currentSslIssuedByCNameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_by_cname);
184 TextView currentSslIssuedByONameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_by_oname);
185 TextView currentSslIssuedByUNameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_by_uname);
186 TextView currentSslStartDateTextView = domainSettingsView.findViewById(R.id.current_website_certificate_start_date);
187 TextView currentSslEndDateTextView = domainSettingsView.findViewById(R.id.current_website_certificate_end_date);
188 TextView noCurrentWebsiteCertificateTextView = domainSettingsView.findViewById(R.id.no_current_website_certificate);
189 ImageView pinnedIpAddressesImageView = domainSettingsView.findViewById(R.id.pinned_ip_addresses_imageview);
190 SwitchCompat pinnedIpAddressesSwitch = domainSettingsView.findViewById(R.id.pinned_ip_addresses_switch);
191 CardView savedIpAddressesCardView = domainSettingsView.findViewById(R.id.saved_ip_addresses_cardview);
192 LinearLayout savedIpAddressesLinearLayout = domainSettingsView.findViewById(R.id.saved_ip_addresses_linearlayout);
193 RadioButton savedIpAddressesRadioButton = domainSettingsView.findViewById(R.id.saved_ip_addresses_radiobutton);
194 TextView savedIpAddressesTextView = domainSettingsView.findViewById(R.id.saved_ip_addresses_textview);
195 CardView currentIpAddressesCardView = domainSettingsView.findViewById(R.id.current_ip_addresses_cardview);
196 LinearLayout currentIpAddressesLinearLayout = domainSettingsView.findViewById(R.id.current_ip_addresses_linearlayout);
197 RadioButton currentIpAddressesRadioButton = domainSettingsView.findViewById(R.id.current_ip_addresses_radiobutton);
198 TextView currentIpAddressesTextView = domainSettingsView.findViewById(R.id.current_ip_addresses_textview);
200 // Setup the pinned labels.
201 String cNameLabel = getString(R.string.common_name) + " ";
202 String oNameLabel = getString(R.string.organization) + " ";
203 String uNameLabel = getString(R.string.organizational_unit) + " ";
204 String startDateLabel = getString(R.string.start_date) + " ";
205 String endDateLabel = getString(R.string.end_date) + " ";
207 // Initialize the database handler. The `0` specifies the database version, but that is ignored and set instead using a constant in `DomainsDatabaseHelper`.
208 DomainsDatabaseHelper domainsDatabaseHelper = new DomainsDatabaseHelper(context, null, null, 0);
210 // Get the database cursor for this ID and move it to the first row.
211 Cursor domainCursor = domainsDatabaseHelper.getCursorForId(databaseId);
212 domainCursor.moveToFirst();
214 // Save the cursor entries as variables.
215 String domainNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.DOMAIN_NAME));
216 int javaScriptInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_JAVASCRIPT));
217 int firstPartyCookiesInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FIRST_PARTY_COOKIES));
218 int thirdPartyCookiesInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_THIRD_PARTY_COOKIES));
219 int domStorageInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_DOM_STORAGE));
220 int formDataInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FORM_DATA)); // Form data can be remove once the minimum API >= 26.
221 int easyListInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_EASYLIST));
222 int easyPrivacyInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_EASYPRIVACY));
223 int fanboysAnnoyanceListInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FANBOYS_ANNOYANCE_LIST));
224 int fanboysSocialBlockingListInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FANBOYS_SOCIAL_BLOCKING_LIST));
225 int ultraListInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ULTRALIST));
226 int ultraPrivacyInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_ULTRAPRIVACY));
227 int blockAllThirdPartyRequestsInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.BLOCK_ALL_THIRD_PARTY_REQUESTS));
228 String currentUserAgentName = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.USER_AGENT));
229 int fontSizeInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.FONT_SIZE));
230 int swipeToRefreshInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.SWIPE_TO_REFRESH));
231 int webViewThemeInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.WEBVIEW_THEME));
232 int wideViewportInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.WIDE_VIEWPORT));
233 int displayImagesInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.DISPLAY_IMAGES));
234 int pinnedSslCertificateInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.PINNED_SSL_CERTIFICATE));
235 String savedSslIssuedToCNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_TO_COMMON_NAME));
236 String savedSslIssuedToONameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_TO_ORGANIZATION));
237 String savedSslIssuedToUNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_TO_ORGANIZATIONAL_UNIT));
238 String savedSslIssuedByCNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_BY_COMMON_NAME));
239 String savedSslIssuedByONameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_BY_ORGANIZATION));
240 String savedSslIssuedByUNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_BY_ORGANIZATIONAL_UNIT));
241 int pinnedIpAddressesInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.PINNED_IP_ADDRESSES));
242 String savedIpAddresses = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.IP_ADDRESSES));
244 // Initialize the saved SSL certificate date variables.
245 Date savedSslStartDate = null;
246 Date savedSslEndDate = null;
248 // Only get the saved SSL certificate dates from the cursor if they are not set to `0`.
249 if (domainCursor.getLong(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_START_DATE)) != 0) {
250 savedSslStartDate = new Date(domainCursor.getLong(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_START_DATE)));
253 if (domainCursor.getLong(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_END_DATE)) != 0) {
254 savedSslEndDate = new Date(domainCursor.getLong(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_END_DATE)));
257 // Create array adapters for the spinners.
258 ArrayAdapter<CharSequence> translatedUserAgentArrayAdapter = ArrayAdapter.createFromResource(context, R.array.translated_domain_settings_user_agent_names, R.layout.spinner_item);
259 ArrayAdapter<CharSequence> fontSizeArrayAdapter = ArrayAdapter.createFromResource(context, R.array.font_size_array, R.layout.spinner_item);
260 ArrayAdapter<CharSequence> swipeToRefreshArrayAdapter = ArrayAdapter.createFromResource(context, R.array.swipe_to_refresh_array, R.layout.spinner_item);
261 ArrayAdapter<CharSequence> webViewThemeArrayAdapter = ArrayAdapter.createFromResource(context, R.array.webview_theme_array, R.layout.spinner_item);
262 ArrayAdapter<CharSequence> wideViewportArrayAdapter = ArrayAdapter.createFromResource(context, R.array.wide_viewport_array, R.layout.spinner_item);
263 ArrayAdapter<CharSequence> displayImagesArrayAdapter = ArrayAdapter.createFromResource(context, R.array.display_webpage_images_array, R.layout.spinner_item);
265 // Set the drop down view resource on the spinners.
266 translatedUserAgentArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items);
267 fontSizeArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items);
268 swipeToRefreshArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items);
269 webViewThemeArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items);
270 wideViewportArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items);
271 displayImagesArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items);
273 // Set the array adapters for the spinners.
274 userAgentSpinner.setAdapter(translatedUserAgentArrayAdapter);
275 fontSizeSpinner.setAdapter(fontSizeArrayAdapter);
276 swipeToRefreshSpinner.setAdapter(swipeToRefreshArrayAdapter);
277 webViewThemeSpinner.setAdapter(webViewThemeArrayAdapter);
278 wideViewportSpinner.setAdapter(wideViewportArrayAdapter);
279 displayWebpageImagesSpinner.setAdapter(displayImagesArrayAdapter);
281 // Create a spannable string builder for each TextView that needs multiple colors of text.
282 SpannableStringBuilder savedSslIssuedToCNameStringBuilder = new SpannableStringBuilder(cNameLabel + savedSslIssuedToCNameString);
283 SpannableStringBuilder savedSslIssuedToONameStringBuilder = new SpannableStringBuilder(oNameLabel + savedSslIssuedToONameString);
284 SpannableStringBuilder savedSslIssuedToUNameStringBuilder = new SpannableStringBuilder(uNameLabel + savedSslIssuedToUNameString);
285 SpannableStringBuilder savedSslIssuedByCNameStringBuilder = new SpannableStringBuilder(cNameLabel + savedSslIssuedByCNameString);
286 SpannableStringBuilder savedSslIssuedByONameStringBuilder = new SpannableStringBuilder(oNameLabel + savedSslIssuedByONameString);
287 SpannableStringBuilder savedSslIssuedByUNameStringBuilder = new SpannableStringBuilder(uNameLabel + savedSslIssuedByUNameString);
289 // Initialize the spannable string builders for the saved SSL certificate dates.
290 SpannableStringBuilder savedSslStartDateStringBuilder;
291 SpannableStringBuilder savedSslEndDateStringBuilder;
293 // Leave the SSL certificate dates empty if they are `null`.
294 if (savedSslStartDate == null) {
295 savedSslStartDateStringBuilder = new SpannableStringBuilder(startDateLabel);
297 savedSslStartDateStringBuilder = new SpannableStringBuilder(startDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(savedSslStartDate));
300 if (savedSslEndDate == null) {
301 savedSslEndDateStringBuilder = new SpannableStringBuilder(endDateLabel);
303 savedSslEndDateStringBuilder = new SpannableStringBuilder(endDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(savedSslEndDate));
306 // Create the foreground color spans.
307 final ForegroundColorSpan blueColorSpan;
308 final ForegroundColorSpan redColorSpan;
310 // Set the color spans according to the theme. The deprecated `getColor()` must be used until the minimum API >= 23.
311 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) {
312 blueColorSpan = new ForegroundColorSpan(resources.getColor(R.color.blue_700));
313 redColorSpan = new ForegroundColorSpan(resources.getColor(R.color.red_a700));
315 blueColorSpan = new ForegroundColorSpan(resources.getColor(R.color.violet_700));
316 redColorSpan = new ForegroundColorSpan(resources.getColor(R.color.red_900));
319 // Set the domain name from the the database cursor.
320 domainNameEditText.setText(domainNameString);
322 // Update the certificates' `Common Name` color when the domain name text changes.
323 domainNameEditText.addTextChangedListener(new TextWatcher() {
325 public void beforeTextChanged(CharSequence s, int start, int count, int after) {
330 public void onTextChanged(CharSequence s, int start, int before, int count) {
335 public void afterTextChanged(Editable s) {
336 // Get the new domain name.
337 String newDomainName = domainNameEditText.getText().toString();
339 // Check the saved SSL certificate against the new domain name.
340 boolean savedSslMatchesNewDomainName = checkDomainNameAgainstCertificate(newDomainName, savedSslIssuedToCNameString);
342 // Create a `SpannableStringBuilder` for the saved certificate `Common Name`.
343 SpannableStringBuilder savedSslCNameStringBuilder = new SpannableStringBuilder(cNameLabel + savedSslIssuedToCNameString);
345 // Format the saved certificate `Common Name` color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
346 if (savedSslMatchesNewDomainName) {
347 savedSslCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), savedSslCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
349 savedSslCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), savedSslCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
352 // Update the saved SSL issued to CName text view.
353 savedSslIssuedToCNameTextView.setText(savedSslCNameStringBuilder);
355 // Update the current website certificate if it exists.
356 if (DomainsActivity.sslIssuedToCName != null) {
357 // Check the current website certificate against the new domain name.
358 boolean currentSslMatchesNewDomainName = checkDomainNameAgainstCertificate(newDomainName, DomainsActivity.sslIssuedToCName);
360 // Create a `SpannableStringBuilder` for the current website certificate `Common Name`.
361 SpannableStringBuilder currentSslCNameStringBuilder = new SpannableStringBuilder(cNameLabel + DomainsActivity.sslIssuedToCName);
363 // Format the current certificate `Common Name` color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
364 if (currentSslMatchesNewDomainName) {
365 currentSslCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), currentSslCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
367 currentSslCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), currentSslCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
370 // Update the current SSL issued to CName text view.
371 currentSslIssuedToCNameTextView.setText(currentSslCNameStringBuilder);
376 // Set the JavaScript switch status.
377 if (javaScriptInt == 1) { // JavaScript is enabled.
378 javaScriptSwitch.setChecked(true);
379 javaScriptImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.javascript_enabled, null));
380 } else { // JavaScript is disabled.
381 javaScriptSwitch.setChecked(false);
382 javaScriptImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.privacy_mode, null));
385 // 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.
386 if (firstPartyCookiesInt == 1) { // First-party cookies are enabled.
387 firstPartyCookiesSwitch.setChecked(true);
388 firstPartyCookiesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.cookies_enabled, null));
389 } else { // First-party cookies are disabled.
390 firstPartyCookiesSwitch.setChecked(false);
392 // Set the icon according to the theme.
393 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
394 firstPartyCookiesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.cookies_disabled_night, null));
396 firstPartyCookiesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.cookies_disabled_day, null));
400 // Only display third-party cookies if SDK_INT >= 21.
401 if (Build.VERSION.SDK_INT >= 21) { // Third-party cookies can be configured for API >= 21.
402 // Only enable third-party-cookies if first-party cookies are enabled.
403 if (firstPartyCookiesInt == 1) { // First-party cookies are enabled.
404 // 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.
405 if (thirdPartyCookiesInt == 1) { // Both first-party and third-party cookies are enabled.
406 // Set the third-party cookies switch to be checked.
407 thirdPartyCookiesSwitch.setChecked(true);
409 // Set the icon to be red.
410 thirdPartyCookiesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.cookies_warning, null));
411 } else { // First party cookies are enabled but third-party cookies are disabled.
412 // Set the third-party cookies switch to be checked.
413 thirdPartyCookiesSwitch.setChecked(false);
415 // Set the icon according to the theme.
416 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
417 thirdPartyCookiesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.cookies_disabled_night, null));
419 thirdPartyCookiesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.cookies_disabled_day, null));
422 } else { // First-party cookies are disabled.
423 // Set the status of third-party cookies.
424 thirdPartyCookiesSwitch.setChecked(thirdPartyCookiesInt == 1);
426 // Disable the third-party cookies switch.
427 thirdPartyCookiesSwitch.setEnabled(false);
429 // Set the icon according to the theme.
430 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
431 thirdPartyCookiesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.cookies_ghosted_night, null));
433 thirdPartyCookiesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.cookies_ghosted_day, null));
436 } else { // Third-party cookies cannot be configured for API <= 21.
437 // Hide the LinearLayout for third-party cookies.
438 thirdPartyCookiesLinearLayout.setVisibility(View.GONE);
441 // Only enable DOM storage if JavaScript is enabled.
442 if (javaScriptInt == 1) { // JavaScript is enabled.
443 // Enable the DOM storage `Switch`.
444 domStorageSwitch.setEnabled(true);
446 // Set the DOM storage status. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
447 if (domStorageInt == 1) { // Both JavaScript and DOM storage are enabled.
448 domStorageSwitch.setChecked(true);
449 domStorageImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.dom_storage_enabled, null));
450 } else { // JavaScript is enabled but DOM storage is disabled.
451 // Set the DOM storage switch to off.
452 domStorageSwitch.setChecked(false);
454 // Set the icon according to the theme.
455 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
456 domStorageImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.dom_storage_disabled_night, null));
458 domStorageImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.dom_storage_disabled_day, null));
461 } else { // JavaScript is disabled.
462 // Disable the DOM storage `Switch`.
463 domStorageSwitch.setEnabled(false);
465 // Set the checked status of DOM storage.
466 domStorageSwitch.setChecked(domStorageInt == 1);
468 // Set the icon according to the theme.
469 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
470 domStorageImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.dom_storage_ghosted_night, null));
472 domStorageImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.dom_storage_ghosted_day, null));
476 // Set the form data visibility. Form data can be removed once the minimum API >= 26.
477 if (Build.VERSION.SDK_INT >= 26) { // Form data no longer applies to newer versions of Android.
478 // Hide the form data image view and switch.
479 formDataImageView.setVisibility(View.GONE);
480 formDataSwitch.setVisibility(View.GONE);
481 } else { // Form data should be displayed because this is an older version of Android.
482 if (formDataInt == 1) { // Form data is on.
483 // Turn the form data switch on.
484 formDataSwitch.setChecked(true);
486 // Set the form data icon.
487 formDataImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.form_data_enabled, null));
488 } else { // Form data is off.
489 // Turn the form data switch to off.
490 formDataSwitch.setChecked(false);
492 // Set the icon according to the theme. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
493 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
494 formDataImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.form_data_disabled_night, null));
496 formDataImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.form_data_disabled_day, null));
501 // Set the EasyList status. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
502 if (easyListInt == 1) { // EasyList is on.
503 // Turn the switch on.
504 easyListSwitch.setChecked(true);
506 // Set the icon according to the theme.
507 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
508 easyListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_ads_enabled_night, null));
510 easyListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_ads_enabled_day, null));
512 } else { // EasyList is off.
513 // Turn the switch off.
514 easyListSwitch.setChecked(false);
516 // Set the icon according to the theme.
517 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
518 easyListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_ads_disabled_night, null));
520 easyListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_ads_disabled_day, null));
524 // Set the EasyPrivacy status. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
525 if (easyPrivacyInt == 1) { // EasyPrivacy is on.
526 // Turn the switch on.
527 easyPrivacySwitch.setChecked(true);
529 // Set the icon according to the theme.
530 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
531 easyPrivacyImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_tracking_enabled_night, null));
533 easyPrivacyImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_tracking_enabled_day, null));
535 } else { // EasyPrivacy is off.
536 // Turn the switch off.
537 easyPrivacySwitch.setChecked(false);
539 // Set the icon according to the theme.
540 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
541 easyPrivacyImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_tracking_disabled_night, null));
543 easyPrivacyImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_tracking_disabled_day, null));
547 // 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.
548 if (fanboysAnnoyanceListInt == 1) { // Fanboy's Annoyance List is on.
549 // Turn the switch on.
550 fanboysAnnoyanceListSwitch.setChecked(true);
552 // Set the icon according to the theme.
553 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
554 fanboysAnnoyanceListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.social_media_enabled_night, null));
556 fanboysAnnoyanceListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.social_media_enabled_day, null));
558 } else { // Fanboy's Annoyance List is off.
559 // Turn the switch off.
560 fanboysAnnoyanceListSwitch.setChecked(false);
562 // Set the icon according to the theme.
563 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
564 fanboysAnnoyanceListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.social_media_disabled_night, null));
566 fanboysAnnoyanceListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.social_media_disabled_day, null));
570 // Only enable Fanboy's Social Blocking List if Fanboy's Annoyance List is off.
571 if (fanboysAnnoyanceListInt == 0) { // Fanboy's Annoyance List is on.
572 // Enable Fanboy's Social Blocking List switch.
573 fanboysSocialBlockingListSwitch.setEnabled(true);
575 // 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.
576 if (fanboysSocialBlockingListInt == 1) { // Fanboy's Social Blocking List is on.
577 // Turn on Fanboy's Social Blocking List switch.
578 fanboysSocialBlockingListSwitch.setChecked(true);
580 // Set the icon according to the theme.
581 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
582 fanboysSocialBlockingListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.social_media_enabled_night, null));
584 fanboysSocialBlockingListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.social_media_enabled_day, null));
586 } else { // Fanboy's Social Blocking List is off.
587 // Turn off Fanboy's Social Blocking List switch.
588 fanboysSocialBlockingListSwitch.setChecked(false);
590 // Set the icon according to the theme.
591 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
592 fanboysSocialBlockingListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.social_media_disabled_night, null));
594 fanboysSocialBlockingListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.social_media_disabled_day, null));
597 } else { // Fanboy's Annoyance List is on.
598 // Disable Fanboy's Social Blocking List switch.
599 fanboysSocialBlockingListSwitch.setEnabled(false);
601 // Set the status of Fanboy's Social Blocking List.
602 fanboysSocialBlockingListSwitch.setChecked(fanboysSocialBlockingListInt == 1);
604 // Set the icon according to the theme.
605 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
606 fanboysSocialBlockingListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.social_media_ghosted_night, null));
608 fanboysSocialBlockingListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.social_media_ghosted_day, null));
612 // Set the UltraList status. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
613 if (ultraListInt == 1) { // UltraList is on.
614 // Turn the switch on.
615 ultraListSwitch.setChecked(true);
617 // Set the icon according to the theme.
618 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
619 ultraListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_ads_enabled_night, null));
621 ultraListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_ads_enabled_day, null));
623 } else { // UltraList is off.
624 // Turn the switch off.
625 ultraListSwitch.setChecked(false);
627 // Set the icon according to the theme.
628 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
629 ultraListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_ads_disabled_night, null));
631 ultraListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_ads_disabled_day, null));
635 // Set the UltraPrivacy status. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
636 if (ultraPrivacyInt == 1) { // UltraPrivacy is on.
637 // Turn the switch on.
638 ultraPrivacySwitch.setChecked(true);
640 // Set the icon according to the theme.
641 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
642 ultraPrivacyImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_tracking_enabled_night, null));
644 ultraPrivacyImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_tracking_enabled_day, null));
646 } else { // EasyPrivacy is off.
647 // Turn the switch off.
648 ultraPrivacySwitch.setChecked(false);
650 // Set the icon according to the theme.
651 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
652 ultraPrivacyImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_tracking_disabled_night, null));
654 ultraPrivacyImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_tracking_disabled_day, null));
658 // 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.
659 if (blockAllThirdPartyRequestsInt == 1) { // Blocking all third-party requests is on.
660 // Turn the switch on.
661 blockAllThirdPartyRequestsSwitch.setChecked(true);
663 // Set the icon according to the theme.
664 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
665 blockAllThirdPartyRequestsImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_all_third_party_requests_enabled_night, null));
667 blockAllThirdPartyRequestsImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_all_third_party_requests_enabled_day, null));
669 } else { // Blocking all third-party requests is off.
670 // Turn the switch off.
671 blockAllThirdPartyRequestsSwitch.setChecked(false);
673 // Set the icon according to the theme.
674 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
675 blockAllThirdPartyRequestsImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_all_third_party_requests_disabled_night, null));
677 blockAllThirdPartyRequestsImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_all_third_party_requests_disabled_day, null));
681 // Inflated a WebView to get the default user agent.
682 // `@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.
683 @SuppressLint("InflateParams") View bareWebViewLayout = inflater.inflate(R.layout.bare_webview, null, false);
684 WebView bareWebView = bareWebViewLayout.findViewById(R.id.bare_webview);
685 final String webViewDefaultUserAgentString = bareWebView.getSettings().getUserAgentString();
687 // Get a handle for the user agent array adapter. This array does not contain the `System default` entry.
688 ArrayAdapter<CharSequence> userAgentNamesArray = ArrayAdapter.createFromResource(context, R.array.user_agent_names, R.layout.spinner_item);
690 // Get the positions of the user agent and the default user agent.
691 int userAgentArrayPosition = userAgentNamesArray.getPosition(currentUserAgentName);
692 int defaultUserAgentArrayPosition = userAgentNamesArray.getPosition(defaultUserAgentName);
694 // Get a handle for the user agent data array. This array does not contain the `System default` entry.
695 String[] userAgentDataArray = resources.getStringArray(R.array.user_agent_data);
697 // Set the user agent text.
698 if (currentUserAgentName.equals(getString(R.string.system_default_user_agent))) { // Use the system default user agent.
699 // Set the user agent according to the system default.
700 switch (defaultUserAgentArrayPosition) {
701 case MainWebViewActivity.UNRECOGNIZED_USER_AGENT: // The default user agent name is not on the canonical list.
702 // This is probably because it was set in an older version of Privacy Browser before the switch to persistent user agent names.
703 userAgentTextView.setText(defaultUserAgentName);
706 case MainWebViewActivity.SETTINGS_WEBVIEW_DEFAULT_USER_AGENT:
707 // Display the `WebView` default user agent.
708 userAgentTextView.setText(webViewDefaultUserAgentString);
711 case MainWebViewActivity.SETTINGS_CUSTOM_USER_AGENT:
712 // Display the custom user agent.
713 userAgentTextView.setText(defaultCustomUserAgentString);
717 // Get the user agent string from the user agent data array.
718 userAgentTextView.setText(userAgentDataArray[defaultUserAgentArrayPosition]);
720 } else if (userAgentArrayPosition == MainWebViewActivity.UNRECOGNIZED_USER_AGENT) { // A custom user agent is stored in the current user agent name.
721 // Set the user agent spinner to `Custom user agent`.
722 userAgentSpinner.setSelection(MainWebViewActivity.DOMAINS_CUSTOM_USER_AGENT);
724 // Hide the user agent TextView.
725 userAgentTextView.setVisibility(View.GONE);
727 // Show the custom user agent EditText and set the current user agent name as the text.
728 customUserAgentEditText.setVisibility(View.VISIBLE);
729 customUserAgentEditText.setText(currentUserAgentName);
730 } else { // The user agent name contains one of the canonical user agents.
731 // 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.
732 userAgentSpinner.setSelection(userAgentArrayPosition + 1);
734 // Show the user agent TextView.
735 userAgentTextView.setVisibility(View.VISIBLE);
737 // Hide the custom user agent EditText.
738 customUserAgentEditText.setVisibility(View.GONE);
740 // Set the user agent text.
741 if (userAgentArrayPosition == MainWebViewActivity.DOMAINS_WEBVIEW_DEFAULT_USER_AGENT) { // The WebView default user agent is selected.
742 // Display the WebView default user agent.
743 userAgentTextView.setText(webViewDefaultUserAgentString);
744 } else { // A user agent besides the default is selected.
745 // 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.
746 userAgentTextView.setText(userAgentDataArray[userAgentArrayPosition + 1]);
750 // Open the user agent spinner when the text view is clicked.
751 userAgentTextView.setOnClickListener((View v) -> {
752 // Open the user agent spinner.
753 userAgentSpinner.performClick();
756 // Display the font size settings.
757 if (fontSizeInt == 0) { // `0` is the code for system default font size.
758 // Set the font size to the system default
759 fontSizeSpinner.setSelection(0);
761 // Show the default font size text view.
762 defaultFontSizeTextView.setVisibility(View.VISIBLE);
764 // Hide the custom font size edit text.
765 customFontSizeEditText.setVisibility(View.GONE);
767 // Set the default font size as the text of the custom font size edit text. This way, if the user switches to custom it will already be populated.
768 customFontSizeEditText.setText(defaultFontSizeString);
769 } else { // A custom font size is selected.
770 // Set the spinner to the custom font size.
771 fontSizeSpinner.setSelection(1);
773 // Hide the default font size text view.
774 defaultFontSizeTextView.setVisibility(View.GONE);
776 // Show the custom font size edit text.
777 customFontSizeEditText.setVisibility(View.GONE);
779 // Set the custom font size.
780 customFontSizeEditText.setText(String.valueOf(fontSizeInt));
783 // Initialize the default font size percentage string.
784 String defaultFontSizePercentageString = defaultFontSizeString + "%";
786 // Set the default font size text in the text view.
787 defaultFontSizeTextView.setText(defaultFontSizePercentageString);
789 // Open the font size spinner when the text view is clicked.
790 defaultFontSizeTextView.setOnClickListener((View v) -> {
791 // Open the user agent spinner.
792 fontSizeSpinner.performClick();
795 // Select the swipe to refresh selection in the spinner.
796 swipeToRefreshSpinner.setSelection(swipeToRefreshInt);
798 // Set the swipe to refresh text.
799 if (defaultSwipeToRefresh) {
800 swipeToRefreshTextView.setText(swipeToRefreshArrayAdapter.getItem(DomainsDatabaseHelper.ENABLED));
802 swipeToRefreshTextView.setText(swipeToRefreshArrayAdapter.getItem(DomainsDatabaseHelper.DISABLED));
805 // 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.
806 switch (swipeToRefreshInt) {
807 case DomainsDatabaseHelper.SYSTEM_DEFAULT:
808 if (defaultSwipeToRefresh) { // Swipe to refresh is enabled by default.
809 // Set the icon according to the theme.
810 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
811 swipeToRefreshImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.refresh_enabled_night, null));
813 swipeToRefreshImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.refresh_enabled_day, null));
815 } else { // Swipe to refresh is disabled by default
816 // Set the icon according to the theme.
817 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
818 swipeToRefreshImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.refresh_disabled_night, null));
820 swipeToRefreshImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.refresh_disabled_day, null));
824 // Show the swipe to refresh TextView.
825 swipeToRefreshTextView.setVisibility(View.VISIBLE);
828 case DomainsDatabaseHelper.ENABLED:
829 // Set the icon according to the theme.
830 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
831 swipeToRefreshImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.refresh_enabled_night, null));
833 swipeToRefreshImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.refresh_enabled_day, null));
836 // Hide the swipe to refresh TextView.`
837 swipeToRefreshTextView.setVisibility(View.GONE);
840 case DomainsDatabaseHelper.DISABLED:
841 // Set the icon according to the theme.
842 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
843 swipeToRefreshImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.refresh_disabled_night, null));
845 swipeToRefreshImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.refresh_disabled_day, null));
848 // Hide the swipe to refresh TextView.
849 swipeToRefreshTextView.setVisibility(View.GONE);
853 // Open the swipe to refresh spinner when the TextView is clicked.
854 swipeToRefreshTextView.setOnClickListener((View v) -> {
855 // Open the swipe to refresh spinner.
856 swipeToRefreshSpinner.performClick();
859 // Get the WebView theme string arrays.
860 String[] webViewThemeStringArray = resources.getStringArray(R.array.webview_theme_array);
861 String[] webViewThemeEntryValuesStringArray = resources.getStringArray(R.array.webview_theme_entry_values);
863 // Define an app WebView theme entry number.
864 int appWebViewThemeEntryNumber;
866 // Get the WebView theme entry number that matches the current WebView theme. A switch statement cannot be used because the WebView theme entry values string array is not a compile time constant.
867 if (defaultWebViewTheme.equals(webViewThemeEntryValuesStringArray[1])) { // The light theme is selected.
868 // Store the default WebView theme entry number.
869 appWebViewThemeEntryNumber = 1;
870 } else if (defaultWebViewTheme.equals(webViewThemeEntryValuesStringArray[2])) { // The dark theme is selected.
871 // Store the default WebView theme entry number.
872 appWebViewThemeEntryNumber = 2;
873 } else { // The system default theme is selected.
874 // Store the default WebView theme entry number.
875 appWebViewThemeEntryNumber = 0;
878 // Set the WebView theme visibility.
879 if (Build.VERSION.SDK_INT < 21) { // The WebView theme cannot be set on API 19.
880 // Get a handle for the webView theme linear layout.
881 LinearLayout webViewThemeLinearLayout = domainSettingsView.findViewById(R.id.webview_theme_linearlayout);
883 // Hide the WebView theme linear layout.
884 webViewThemeLinearLayout.setVisibility(View.GONE);
885 } else { // The WebView theme can be set on API >= 21.
886 // Select the WebView theme in the spinner.
887 webViewThemeSpinner.setSelection(webViewThemeInt);
889 // Set the WebView theme text.
890 if (appWebViewThemeEntryNumber == DomainsDatabaseHelper.SYSTEM_DEFAULT) { // The app WebView theme is system default.
891 // Set the text according to the current UI theme.
892 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) {
893 webViewThemeTextView.setText(webViewThemeStringArray[DomainsDatabaseHelper.LIGHT_THEME]);
895 webViewThemeTextView.setText(webViewThemeStringArray[DomainsDatabaseHelper.DARK_THEME]);
897 } else { // The app WebView theme is not system default.
898 // Set the text according to the app WebView theme.
899 webViewThemeTextView.setText(webViewThemeStringArray[appWebViewThemeEntryNumber]);
902 // Set the WebView theme icon and text visibility. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
903 switch (webViewThemeInt) {
904 case DomainsDatabaseHelper.SYSTEM_DEFAULT: // The domain WebView theme is system default.
905 // Set the icon according to the app WebView theme.
906 switch (appWebViewThemeEntryNumber) {
907 case DomainsDatabaseHelper.SYSTEM_DEFAULT: // The default WebView theme is system default.
908 // Set the icon according to the app theme.
909 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) {
910 // Set the light mode icon.
911 webViewThemeImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.webview_light_theme_day, null));
913 // Set the dark theme icon.
914 webViewThemeImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.webview_dark_theme_night, null));
918 case DomainsDatabaseHelper.LIGHT_THEME: // the default WebView theme is light.
919 // Set the icon according to the app theme.
920 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) {
921 webViewThemeImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.webview_light_theme_day, null));
923 webViewThemeImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.webview_light_theme_night, null));
927 case DomainsDatabaseHelper.DARK_THEME: // the default WebView theme is dark.
928 // Set the icon according to the app theme.
929 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) {
930 webViewThemeImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.webview_dark_theme_day, null));
932 webViewThemeImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.webview_dark_theme_night, null)); }
936 // Show the WebView theme text view.
937 webViewThemeTextView.setVisibility(View.VISIBLE);
940 case DomainsDatabaseHelper.LIGHT_THEME: // The domain WebView theme is light.
941 // Set the icon according to the app theme.
942 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) {
943 webViewThemeImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.webview_light_theme_day, null));
945 webViewThemeImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.webview_light_theme_night, null));
948 // Hide the WebView theme text view.
949 webViewThemeTextView.setVisibility(View.GONE);
952 case DomainsDatabaseHelper.DARK_THEME: // The domain WebView theme is dark.
953 // Set the icon according to the app theme.
954 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) {
955 webViewThemeImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.webview_dark_theme_day, null));
957 webViewThemeImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.webview_dark_theme_night, null));
960 // Hide the WebView theme text view.
961 webViewThemeTextView.setVisibility(View.GONE);
965 // Open the WebView theme spinner when the text view is clicked.
966 webViewThemeTextView.setOnClickListener((View v) -> {
967 // Open the WebView theme spinner.
968 webViewThemeSpinner.performClick();
972 // Select the wide viewport in the spinner.
973 wideViewportSpinner.setSelection(wideViewportInt);
975 // Set the default wide viewport text.
976 if (defaultWideViewport) {
977 wideViewportTextView.setText(wideViewportArrayAdapter.getItem(DomainsDatabaseHelper.ENABLED));
979 wideViewportTextView.setText(wideViewportArrayAdapter.getItem(DomainsDatabaseHelper.DISABLED));
982 // Set the wide viewport icon and text view settings. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
983 switch (wideViewportInt) {
984 case DomainsDatabaseHelper.SYSTEM_DEFAULT:
985 if (defaultWideViewport) { // Wide viewport enabled by default.
986 // Set the icon according to the theme.
987 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
988 wideViewportImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.wide_viewport_enabled_night, null));
990 wideViewportImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.wide_viewport_enabled_day, null));
992 } else { // Wide viewport disabled by default.
993 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
994 wideViewportImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.wide_viewport_disabled_night, null));
996 wideViewportImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.wide_viewport_disabled_day, null));
1000 // Show the wide viewport text view.
1001 wideViewportTextView.setVisibility(View.VISIBLE);
1004 case DomainsDatabaseHelper.ENABLED:
1005 // Set the icon according to the theme.
1006 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1007 wideViewportImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.wide_viewport_enabled_night, null));
1009 wideViewportImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.wide_viewport_enabled_day, null));
1012 // Hide the wide viewport text view.
1013 wideViewportTextView.setVisibility(View.GONE);
1016 case DomainsDatabaseHelper.DISABLED:
1017 // Set the icon according to the theme.
1018 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1019 wideViewportImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.wide_viewport_disabled_night, null));
1021 wideViewportImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.wide_viewport_disabled_day, null));
1024 // Hide the wide viewport text view.
1025 wideViewportTextView.setVisibility(View.GONE);
1029 // Open the wide viewport spinner when the text view is clicked.
1030 wideViewportTextView.setOnClickListener((View view) -> {
1031 // Open the wide viewport spinner.
1032 wideViewportSpinner.performClick();
1035 // Display the website images mode in the spinner.
1036 displayWebpageImagesSpinner.setSelection(displayImagesInt);
1038 // Set the default display images text.
1039 if (defaultDisplayWebpageImages) {
1040 displayImagesTextView.setText(displayImagesArrayAdapter.getItem(DomainsDatabaseHelper.ENABLED));
1042 displayImagesTextView.setText(displayImagesArrayAdapter.getItem(DomainsDatabaseHelper.DISABLED));
1045 // Set the display website images icon and text view settings. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
1046 switch (displayImagesInt) {
1047 case DomainsDatabaseHelper.SYSTEM_DEFAULT:
1048 if (defaultDisplayWebpageImages) { // Display webpage images enabled by default.
1049 // Set the icon according to the theme.
1050 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1051 displayWebpageImagesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.images_enabled_night, null));
1053 displayWebpageImagesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.images_enabled_day, null));
1055 } else { // Display webpage images disabled by default.
1056 // Set the icon according to the theme.
1057 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1058 displayWebpageImagesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.images_disabled_night, null));
1060 displayWebpageImagesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.images_disabled_day, null));
1064 // Show the display images text view.
1065 displayImagesTextView.setVisibility(View.VISIBLE);
1068 case DomainsDatabaseHelper.ENABLED:
1069 // Set the icon according to the theme.
1070 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1071 displayWebpageImagesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.images_enabled_night, null));
1073 displayWebpageImagesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.images_enabled_day, null));
1076 // Hide the display images text view.
1077 displayImagesTextView.setVisibility(View.GONE);
1080 case DomainsDatabaseHelper.DISABLED:
1081 // Set the icon according to the theme.
1082 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1083 displayWebpageImagesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.images_disabled_night, null));
1085 displayWebpageImagesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.images_disabled_day, null));
1088 // Hide the display images text view.
1089 displayImagesTextView.setVisibility(View.GONE);
1093 // Open the display images spinner when the text view is clicked.
1094 displayImagesTextView.setOnClickListener((View view) -> {
1095 // Open the user agent spinner.
1096 displayWebpageImagesSpinner.performClick();
1099 // Set the pinned SSL certificate icon.
1100 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.
1101 // Check the switch.
1102 pinnedSslCertificateSwitch.setChecked(true);
1104 // Set the icon according to the theme.
1105 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1106 pinnedSslCertificateImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.ssl_certificate_enabled_night, null));
1108 pinnedSslCertificateImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.ssl_certificate_enabled_day, null));
1110 } else { // Pinned SSL certificate is disabled.
1111 // Uncheck the switch.
1112 pinnedSslCertificateSwitch.setChecked(false);
1114 // Set the icon according to the theme.
1115 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1116 pinnedSslCertificateImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.ssl_certificate_disabled_night, null));
1118 pinnedSslCertificateImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.ssl_certificate_disabled_day, null));
1122 // Store the current date.
1123 Date currentDate = Calendar.getInstance().getTime();
1125 // Setup the string builders to display the general certificate information in blue. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
1126 savedSslIssuedToONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), savedSslIssuedToONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1127 savedSslIssuedToUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), savedSslIssuedToUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1128 savedSslIssuedByCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), savedSslIssuedByCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1129 savedSslIssuedByONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), savedSslIssuedByONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1130 savedSslIssuedByUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), savedSslIssuedByUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1132 // Check the certificate Common Name against the domain name.
1133 boolean savedSslCommonNameMatchesDomainName = checkDomainNameAgainstCertificate(domainNameString, savedSslIssuedToCNameString);
1135 // Format the issued to Common Name color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
1136 if (savedSslCommonNameMatchesDomainName) {
1137 savedSslIssuedToCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), savedSslIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1139 savedSslIssuedToCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), savedSslIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1142 // Format the start date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
1143 if ((savedSslStartDate != null) && savedSslStartDate.after(currentDate)) { // The certificate start date is in the future.
1144 savedSslStartDateStringBuilder.setSpan(redColorSpan, startDateLabel.length(), savedSslStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1145 } else { // The certificate start date is in the past.
1146 savedSslStartDateStringBuilder.setSpan(blueColorSpan, startDateLabel.length(), savedSslStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1149 // Format the end date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
1150 if ((savedSslEndDate != null) && savedSslEndDate.before(currentDate)) { // The certificate end date is in the past.
1151 savedSslEndDateStringBuilder.setSpan(redColorSpan, endDateLabel.length(), savedSslEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1152 } else { // The certificate end date is in the future.
1153 savedSslEndDateStringBuilder.setSpan(blueColorSpan, endDateLabel.length(), savedSslEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1156 // Display the saved website SSL certificate strings.
1157 savedSslIssuedToCNameTextView.setText(savedSslIssuedToCNameStringBuilder);
1158 savedSslIssuedToONameTextView.setText(savedSslIssuedToONameStringBuilder);
1159 savedSslIssuedToUNameTextView.setText(savedSslIssuedToUNameStringBuilder);
1160 savedSslIssuedByCNameTextView.setText(savedSslIssuedByCNameStringBuilder);
1161 savedSslIssuedByONameTextView.setText(savedSslIssuedByONameStringBuilder);
1162 savedSslIssuedByUNameTextView.setText(savedSslIssuedByUNameStringBuilder);
1163 savedSslStartDateTextView.setText(savedSslStartDateStringBuilder);
1164 savedSslEndDateTextView.setText(savedSslEndDateStringBuilder);
1166 // Populate the current website SSL certificate if there is one.
1167 if (DomainsActivity.sslIssuedToCName != null) {
1168 // Get dates from the raw long values.
1169 Date currentSslStartDate = new Date(DomainsActivity.sslStartDateLong);
1170 Date currentSslEndDate = new Date(DomainsActivity.sslEndDateLong);
1172 // Create a spannable string builder for each text view that needs multiple colors of text.
1173 SpannableStringBuilder currentSslIssuedToCNameStringBuilder = new SpannableStringBuilder(cNameLabel + DomainsActivity.sslIssuedToCName);
1174 SpannableStringBuilder currentSslIssuedToONameStringBuilder = new SpannableStringBuilder(oNameLabel + DomainsActivity.sslIssuedToOName);
1175 SpannableStringBuilder currentSslIssuedToUNameStringBuilder = new SpannableStringBuilder(uNameLabel + DomainsActivity.sslIssuedToUName);
1176 SpannableStringBuilder currentSslIssuedByCNameStringBuilder = new SpannableStringBuilder(cNameLabel + DomainsActivity.sslIssuedByCName);
1177 SpannableStringBuilder currentSslIssuedByONameStringBuilder = new SpannableStringBuilder(oNameLabel + DomainsActivity.sslIssuedByOName);
1178 SpannableStringBuilder currentSslIssuedByUNameStringBuilder = new SpannableStringBuilder(uNameLabel + DomainsActivity.sslIssuedByUName);
1179 SpannableStringBuilder currentSslStartDateStringBuilder = new SpannableStringBuilder(startDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG)
1180 .format(currentSslStartDate));
1181 SpannableStringBuilder currentSslEndDateStringBuilder = new SpannableStringBuilder(endDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG)
1182 .format(currentSslEndDate));
1184 // Setup the string builders to display the general certificate information in blue. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
1185 currentSslIssuedToONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), currentSslIssuedToONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1186 currentSslIssuedToUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), currentSslIssuedToUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1187 currentSslIssuedByCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), currentSslIssuedByCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1188 currentSslIssuedByONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), currentSslIssuedByONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1189 currentSslIssuedByUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), currentSslIssuedByUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1191 // Check the certificate Common Name against the domain name.
1192 boolean currentSslCommonNameMatchesDomainName = checkDomainNameAgainstCertificate(domainNameString, DomainsActivity.sslIssuedToCName);
1194 // Format the issued to Common Name color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
1195 if (currentSslCommonNameMatchesDomainName) {
1196 currentSslIssuedToCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), currentSslIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1198 currentSslIssuedToCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), currentSslIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1201 // Format the start date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
1202 if (currentSslStartDate.after(currentDate)) { // The certificate start date is in the future.
1203 currentSslStartDateStringBuilder.setSpan(redColorSpan, startDateLabel.length(), currentSslStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1204 } else { // The certificate start date is in the past.
1205 currentSslStartDateStringBuilder.setSpan(blueColorSpan, startDateLabel.length(), currentSslStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1208 // Format the end date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
1209 if (currentSslEndDate.before(currentDate)) { // The certificate end date is in the past.
1210 currentSslEndDateStringBuilder.setSpan(redColorSpan, endDateLabel.length(), currentSslEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1211 } else { // The certificate end date is in the future.
1212 currentSslEndDateStringBuilder.setSpan(blueColorSpan, endDateLabel.length(), currentSslEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1215 // Display the current website SSL certificate strings.
1216 currentSslIssuedToCNameTextView.setText(currentSslIssuedToCNameStringBuilder);
1217 currentSslIssuedToONameTextView.setText(currentSslIssuedToONameStringBuilder);
1218 currentSslIssuedToUNameTextView.setText(currentSslIssuedToUNameStringBuilder);
1219 currentSslIssuedByCNameTextView.setText(currentSslIssuedByCNameStringBuilder);
1220 currentSslIssuedByONameTextView.setText(currentSslIssuedByONameStringBuilder);
1221 currentSslIssuedByUNameTextView.setText(currentSslIssuedByUNameStringBuilder);
1222 currentSslStartDateTextView.setText(currentSslStartDateStringBuilder);
1223 currentSslEndDateTextView.setText(currentSslEndDateStringBuilder);
1226 // Set the initial display status of the SSL certificates card views.
1227 if (pinnedSslCertificateSwitch.isChecked()) { // An SSL certificate is pinned.
1228 // Set the visibility of the saved SSL certificate.
1229 if (savedSslIssuedToCNameString == null) {
1230 savedSslCardView.setVisibility(View.GONE);
1232 savedSslCardView.setVisibility(View.VISIBLE);
1235 // Set the visibility of the current website SSL certificate.
1236 if (DomainsActivity.sslIssuedToCName == null) { // There is no current SSL certificate.
1237 // Hide the SSL certificate.
1238 currentSslCardView.setVisibility(View.GONE);
1240 // Show the instruction.
1241 noCurrentWebsiteCertificateTextView.setVisibility(View.VISIBLE);
1242 } else { // There is a current SSL certificate.
1243 // Show the SSL certificate.
1244 currentSslCardView.setVisibility(View.VISIBLE);
1246 // Hide the instruction.
1247 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
1250 // Set the status of the radio buttons and the card view backgrounds.
1251 if (savedSslCardView.getVisibility() == View.VISIBLE) { // The saved SSL certificate is displayed.
1252 // Check the saved SSL certificate radio button.
1253 savedSslCertificateRadioButton.setChecked(true);
1255 // Uncheck the current website SSL certificate radio button.
1256 currentWebsiteCertificateRadioButton.setChecked(false);
1258 // Darken the background of the current website SSL certificate linear layout according to the theme.
1259 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1260 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1262 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1264 } else if (currentSslCardView.getVisibility() == View.VISIBLE) { // The saved SSL certificate is hidden but the current website SSL certificate is visible.
1265 // Check the current website SSL certificate radio button.
1266 currentWebsiteCertificateRadioButton.setChecked(true);
1268 // Uncheck the saved SSL certificate radio button.
1269 savedSslCertificateRadioButton.setChecked(false);
1270 } else { // Neither SSL certificate is visible.
1271 // Uncheck both radio buttons.
1272 savedSslCertificateRadioButton.setChecked(false);
1273 currentWebsiteCertificateRadioButton.setChecked(false);
1275 } else { // An SSL certificate is not pinned.
1276 // Hide the SSl certificates and instructions.
1277 savedSslCardView.setVisibility(View.GONE);
1278 currentSslCardView.setVisibility(View.GONE);
1279 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
1281 // Uncheck the radio buttons.
1282 savedSslCertificateRadioButton.setChecked(false);
1283 currentWebsiteCertificateRadioButton.setChecked(false);
1286 // Set the pinned IP addresses icon.
1287 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.
1288 // Check the switch.
1289 pinnedIpAddressesSwitch.setChecked(true);
1291 // Set the icon according to the theme.
1292 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1293 pinnedIpAddressesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.ssl_certificate_enabled_night, null));
1295 pinnedIpAddressesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.ssl_certificate_enabled_day, null));
1297 } else { // Pinned IP Addresses is disabled.
1298 // Uncheck the switch.
1299 pinnedIpAddressesSwitch.setChecked(false);
1301 // Set the icon according to the theme.
1302 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1303 pinnedIpAddressesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.ssl_certificate_disabled_night, null));
1305 pinnedIpAddressesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.ssl_certificate_disabled_day, null));
1309 // Populate the saved and current IP addresses.
1310 savedIpAddressesTextView.setText(savedIpAddresses);
1311 currentIpAddressesTextView.setText(DomainsActivity.currentIpAddresses);
1313 // Set the initial display status of the IP addresses card views.
1314 if (pinnedIpAddressesSwitch.isChecked()) { // IP addresses are pinned.
1315 // Set the visibility of the saved IP addresses.
1316 if (savedIpAddresses == null) { // There are no saved IP addresses.
1317 savedIpAddressesCardView.setVisibility(View.GONE);
1318 } else { // There are saved IP addresses.
1319 savedIpAddressesCardView.setVisibility(View.VISIBLE);
1322 // Set the visibility of the current IP addresses.
1323 currentIpAddressesCardView.setVisibility(View.VISIBLE);
1325 // Set the status of the radio buttons and the card view backgrounds.
1326 if (savedIpAddressesCardView.getVisibility() == View.VISIBLE) { // The saved IP addresses are displayed.
1327 // Check the saved IP addresses radio button.
1328 savedIpAddressesRadioButton.setChecked(true);
1330 // Uncheck the current IP addresses radio button.
1331 currentIpAddressesRadioButton.setChecked(false);
1333 // Darken the background of the current IP addresses linear layout according to the theme.
1334 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1335 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1337 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1339 } else { // The saved IP addresses are hidden.
1340 // Check the current IP addresses radio button.
1341 currentIpAddressesRadioButton.setChecked(true);
1343 // Uncheck the saved IP addresses radio button.
1344 savedIpAddressesRadioButton.setChecked(false);
1346 } else { // IP addresses are not pinned.
1347 // Hide the IP addresses card views.
1348 savedIpAddressesCardView.setVisibility(View.GONE);
1349 currentIpAddressesCardView.setVisibility(View.GONE);
1351 // Uncheck the radio buttons.
1352 savedIpAddressesRadioButton.setChecked(false);
1353 currentIpAddressesRadioButton.setChecked(false);
1357 // Set the JavaScript switch listener.
1358 javaScriptSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1359 if (isChecked) { // JavaScript is enabled.
1360 // Update the JavaScript icon.
1361 javaScriptImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.javascript_enabled, null));
1363 // Enable the DOM storage `Switch`.
1364 domStorageSwitch.setEnabled(true);
1366 // Update the DOM storage icon.
1367 if (domStorageSwitch.isChecked()) { // DOM storage is enabled.
1368 domStorageImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.dom_storage_enabled, null));
1369 } else { // DOM storage is disabled.
1370 // Set the icon according to the theme.
1371 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1372 domStorageImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.dom_storage_disabled_night, null));
1374 domStorageImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.dom_storage_disabled_day, null));
1377 } else { // JavaScript is disabled.
1378 // Update the JavaScript icon.
1379 javaScriptImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.privacy_mode, null));
1381 // Disable the DOM storage `Switch`.
1382 domStorageSwitch.setEnabled(false);
1384 // Set the DOM storage icon according to the theme.
1385 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1386 domStorageImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.dom_storage_ghosted_night, null));
1388 domStorageImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.dom_storage_ghosted_day, null));
1393 // Set the first-party cookies switch listener.
1394 firstPartyCookiesSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1395 if (isChecked) { // First-party cookies are enabled.
1396 // Update the first-party cookies icon.
1397 firstPartyCookiesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.cookies_enabled, null));
1399 // Enable the third-party cookies switch.
1400 thirdPartyCookiesSwitch.setEnabled(true);
1402 // Update the third-party cookies icon.
1403 if (thirdPartyCookiesSwitch.isChecked()) { // Third-party cookies are enabled.
1404 // Set the third-party cookies icon to be red.
1405 thirdPartyCookiesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.cookies_warning, null));
1406 } else { // Third-party cookies are disabled.
1407 // Set the third-party cookies icon according to the theme.
1408 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1409 thirdPartyCookiesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.cookies_disabled_night, null));
1411 thirdPartyCookiesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.cookies_disabled_day, null));
1414 } else { // First-party cookies are disabled.
1415 // Update the first-party cookies icon according to the theme.
1416 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1417 firstPartyCookiesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.cookies_disabled_night, null));
1419 firstPartyCookiesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.cookies_disabled_day, null));
1422 // Disable the third-party cookies switch.
1423 thirdPartyCookiesSwitch.setEnabled(false);
1425 // Set the third-party cookies icon according to the theme.
1426 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1427 thirdPartyCookiesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.cookies_ghosted_night, null));
1429 thirdPartyCookiesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.cookies_ghosted_day, null));
1434 // Set the third-party cookies switch listener.
1435 thirdPartyCookiesSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1438 // Set the third-party cookies icon to be red.
1439 thirdPartyCookiesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.cookies_warning, null));
1441 // Update the third-party cookies icon according to the theme.
1442 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1443 thirdPartyCookiesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.cookies_disabled_night, null));
1445 thirdPartyCookiesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.cookies_disabled_day, null));
1450 // Set the DOM Storage switch listener.
1451 domStorageSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1454 domStorageImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.dom_storage_enabled, null));
1456 // Set the icon according to the theme.
1457 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1458 domStorageImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.dom_storage_disabled_night, null));
1460 domStorageImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.dom_storage_disabled_day, null));
1465 // Set the form data switch listener. It can be removed once the minimum API >= 26.
1466 if (Build.VERSION.SDK_INT < 26) {
1467 formDataSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1470 formDataImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.form_data_enabled, null));
1472 // Set the icon according to the theme.
1473 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1474 formDataImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.form_data_disabled_night, null));
1476 formDataImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.form_data_disabled_day, null));
1482 // Set the EasyList switch listener.
1483 easyListSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1485 if (isChecked) { // EasyList is on.
1486 // Set the icon according to the theme.
1487 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1488 easyListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_ads_enabled_night, null));
1490 easyListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_ads_enabled_day, null));
1492 } else { // EasyList is off.
1493 // Set the icon according to the theme.
1494 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1495 easyListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_ads_disabled_night, null));
1497 easyListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_ads_disabled_day, null));
1502 // Set the EasyPrivacy switch listener.
1503 easyPrivacySwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1505 if (isChecked) { // EasyPrivacy is on.
1506 // Set the icon according to the theme.
1507 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1508 easyPrivacyImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_tracking_enabled_night, null));
1510 easyPrivacyImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_tracking_enabled_day, null));
1512 } else { // EasyPrivacy is off.
1513 // Set the icon according to the theme.
1514 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1515 easyPrivacyImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_tracking_disabled_night, null));
1517 easyPrivacyImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_tracking_disabled_day, null));
1522 // Set the Fanboy's Annoyance List switch listener.
1523 fanboysAnnoyanceListSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1524 // Update the icon and Fanboy's Social Blocking List.
1525 if (isChecked) { // Fanboy's Annoyance List is on.
1526 // Set the icon according to the theme.
1527 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1528 fanboysAnnoyanceListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.social_media_enabled_night, null));
1530 fanboysAnnoyanceListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.social_media_enabled_day, null));
1533 // Disable the Fanboy's Social Blocking List switch.
1534 fanboysSocialBlockingListSwitch.setEnabled(false);
1536 // Update the Fanboy's Social Blocking List icon according to the theme.
1537 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1538 fanboysSocialBlockingListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.social_media_ghosted_night, null));
1540 fanboysSocialBlockingListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.social_media_ghosted_day, null));
1542 } else { // Fanboy's Annoyance List is off.
1543 // Set the icon according to the theme.
1544 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1545 fanboysAnnoyanceListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.social_media_disabled_night, null));
1547 fanboysAnnoyanceListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.social_media_disabled_day, null));
1550 // Enable the Fanboy's Social Blocking List switch.
1551 fanboysSocialBlockingListSwitch.setEnabled(true);
1553 // Update the Fanboy's Social Blocking List icon.
1554 if (fanboysSocialBlockingListSwitch.isChecked()) { // Fanboy's Social Blocking List is on.
1555 // Update the icon according to the theme.
1556 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1557 fanboysSocialBlockingListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.social_media_enabled_night, null));
1559 fanboysSocialBlockingListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.social_media_enabled_day, null));
1561 } else { // Fanboy's Social Blocking List is off.
1562 // Update the icon according to the theme.
1563 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1564 fanboysSocialBlockingListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.social_media_disabled_night, null));
1566 fanboysSocialBlockingListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.social_media_disabled_day, null));
1573 // Set the Fanboy's Social Blocking List switch listener.
1574 fanboysSocialBlockingListSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1576 if (isChecked) { // Fanboy's Social Blocking List is on.
1577 // Set the icon according to the theme.
1578 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1579 fanboysSocialBlockingListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.social_media_enabled_night, null));
1581 fanboysSocialBlockingListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.social_media_enabled_day, null));
1583 } else { // Fanboy's Social Blocking List is off.
1584 // Set the icon according to the theme.
1585 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1586 fanboysSocialBlockingListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.social_media_disabled_night, null));
1588 fanboysSocialBlockingListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.social_media_disabled_day, null));
1593 // Set the UltraList switch listener.
1594 ultraListSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1596 if (isChecked) { // UltraList is on.
1597 // Set the icon according to the theme.
1598 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1599 ultraListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_ads_enabled_night, null));
1601 ultraListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_ads_enabled_day, null));
1603 } else { // UltraList is off.
1604 // Set the icon according to the theme.
1605 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1606 ultraListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_ads_disabled_night, null));
1608 ultraListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_ads_disabled_day, null));
1613 // Set the UltraPrivacy switch listener.
1614 ultraPrivacySwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1616 if (isChecked) { // UltraPrivacy is on.
1617 // Set the icon according to the theme.
1618 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1619 ultraPrivacyImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_tracking_enabled_night, null));
1621 ultraPrivacyImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_tracking_enabled_day, null));
1623 } else { // UltraPrivacy is off.
1624 // Set the icon according to the theme.
1625 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1626 ultraPrivacyImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_tracking_disabled_night, null));
1628 ultraPrivacyImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_tracking_disabled_day, null));
1633 // Set the block all third-party requests switch listener.
1634 blockAllThirdPartyRequestsSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1636 if (isChecked) { // Blocking all third-party requests is on.
1637 // Set the icon according to the theme.
1638 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1639 blockAllThirdPartyRequestsImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_all_third_party_requests_enabled_night, null));
1641 blockAllThirdPartyRequestsImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_all_third_party_requests_enabled_day, null));
1643 } else { // Blocking all third-party requests is off.
1644 // Set the icon according to the theme.
1645 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1646 blockAllThirdPartyRequestsImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_all_third_party_requests_disabled_night, null));
1648 blockAllThirdPartyRequestsImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_all_third_party_requests_disabled_day, null));
1653 // Set the user agent spinner listener.
1654 userAgentSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1656 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1657 // Set the new user agent.
1659 case MainWebViewActivity.DOMAINS_SYSTEM_DEFAULT_USER_AGENT:
1660 // Show the user agent TextView.
1661 userAgentTextView.setVisibility(View.VISIBLE);
1663 // Hide the custom user agent EditText.
1664 customUserAgentEditText.setVisibility(View.GONE);
1666 // Set the user text.
1667 switch (defaultUserAgentArrayPosition) {
1668 case MainWebViewActivity.UNRECOGNIZED_USER_AGENT: // The default user agent name is not on the canonical list.
1669 // This is probably because it was set in an older version of Privacy Browser before the switch to persistent user agent names.
1670 userAgentTextView.setText(defaultUserAgentName);
1673 case MainWebViewActivity.SETTINGS_WEBVIEW_DEFAULT_USER_AGENT:
1674 // Display the `WebView` default user agent.
1675 userAgentTextView.setText(webViewDefaultUserAgentString);
1678 case MainWebViewActivity.SETTINGS_CUSTOM_USER_AGENT:
1679 // Display the custom user agent.
1680 userAgentTextView.setText(defaultCustomUserAgentString);
1684 // Get the user agent string from the user agent data array.
1685 userAgentTextView.setText(userAgentDataArray[defaultUserAgentArrayPosition]);
1689 case MainWebViewActivity.DOMAINS_WEBVIEW_DEFAULT_USER_AGENT:
1690 // Show the user agent TextView and set the text.
1691 userAgentTextView.setVisibility(View.VISIBLE);
1692 userAgentTextView.setText(webViewDefaultUserAgentString);
1694 // Hide the custom user agent EditTex.
1695 customUserAgentEditText.setVisibility(View.GONE);
1698 case MainWebViewActivity.DOMAINS_CUSTOM_USER_AGENT:
1699 // Hide the user agent TextView.
1700 userAgentTextView.setVisibility(View.GONE);
1702 // Show the custom user agent EditText and set the current user agent name as the text.
1703 customUserAgentEditText.setVisibility(View.VISIBLE);
1704 customUserAgentEditText.setText(currentUserAgentName);
1708 // 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.
1709 userAgentTextView.setVisibility(View.VISIBLE);
1710 userAgentTextView.setText(userAgentDataArray[position - 1]);
1712 // Hide `customUserAgentEditText`.
1713 customUserAgentEditText.setVisibility(View.GONE);
1718 public void onNothingSelected(AdapterView<?> parent) {
1723 // Set the font size spinner listener.
1724 fontSizeSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1726 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1727 // Update the font size display options.
1728 if (position == 0) { // The system default font size has been selected.
1729 // Show the default font size text view.
1730 defaultFontSizeTextView.setVisibility(View.VISIBLE);
1732 // Hide the custom font size edit text.
1733 customFontSizeEditText.setVisibility(View.GONE);
1734 } else { // A custom font size has been selected.
1735 // Hide the default font size text view.
1736 defaultFontSizeTextView.setVisibility(View.GONE);
1738 // Show the custom font size edit text.
1739 customFontSizeEditText.setVisibility(View.VISIBLE);
1744 public void onNothingSelected(AdapterView<?> parent) {
1749 // Set the swipe to refresh spinner listener.
1750 swipeToRefreshSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1752 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1753 // 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.
1755 case DomainsDatabaseHelper.SYSTEM_DEFAULT:
1756 if (defaultSwipeToRefresh) { // Swipe to refresh enabled by default.
1757 // Set the icon according to the theme.
1758 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1759 swipeToRefreshImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.refresh_enabled_night, null));
1761 swipeToRefreshImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.refresh_enabled_day, null));
1763 } else { // Swipe to refresh disabled by default.
1764 // Set the icon according to the theme.
1765 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1766 swipeToRefreshImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.refresh_disabled_night, null));
1768 swipeToRefreshImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.refresh_disabled_day, null));
1772 // Show the swipe to refresh TextView.
1773 swipeToRefreshTextView.setVisibility(View.VISIBLE);
1776 case DomainsDatabaseHelper.ENABLED:
1777 // Set the icon according to the theme.
1778 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1779 swipeToRefreshImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.refresh_enabled_night, null));
1781 swipeToRefreshImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.refresh_enabled_day, null));
1784 // Hide the swipe to refresh TextView.
1785 swipeToRefreshTextView.setVisibility(View.GONE);
1788 case DomainsDatabaseHelper.DISABLED:
1789 // Set the icon according to the theme.
1790 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1791 swipeToRefreshImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.refresh_disabled_night, null));
1793 swipeToRefreshImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.refresh_disabled_day, null));
1796 // Hide the swipe to refresh TextView.
1797 swipeToRefreshTextView.setVisibility(View.GONE);
1802 public void onNothingSelected(AdapterView<?> parent) {
1807 // Set the WebView theme spinner listener.
1808 webViewThemeSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1810 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1811 // Update the icon and the visibility of the WebView theme text view. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
1813 case DomainsDatabaseHelper.SYSTEM_DEFAULT: // the domain WebView theme is system default.
1814 // Set the icon according to the app WebView theme.
1815 switch (appWebViewThemeEntryNumber) {
1816 case DomainsDatabaseHelper.SYSTEM_DEFAULT: // The default WebView theme is system default.
1817 // Set the icon according to the app theme.
1818 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) {
1819 // Set the light mode icon.
1820 webViewThemeImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.webview_light_theme_day, null));
1822 // Set the dark theme icon.
1823 webViewThemeImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.webview_dark_theme_night, null));
1827 case DomainsDatabaseHelper.LIGHT_THEME: // The default WebView theme is light.
1828 // Set the icon according to the app theme.
1829 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) {
1830 webViewThemeImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.webview_light_theme_day, null));
1832 webViewThemeImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.webview_light_theme_night, null));
1836 case DomainsDatabaseHelper.DARK_THEME: // The default WebView theme is dark.
1837 // Set the icon according to the app theme.
1838 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) {
1839 webViewThemeImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.webview_dark_theme_day, null));
1841 webViewThemeImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.webview_dark_theme_night, null));
1846 // Show the WebView theme text view.
1847 webViewThemeTextView.setVisibility(View.VISIBLE);
1850 case DomainsDatabaseHelper.LIGHT_THEME: // The domain WebView theme is light.
1851 // Set the icon according to the app theme.
1852 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) {
1853 webViewThemeImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.webview_light_theme_day, null));
1855 webViewThemeImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.webview_light_theme_night, null));
1858 // Hide the WebView theme text view.
1859 webViewThemeTextView.setVisibility(View.GONE);
1862 case DomainsDatabaseHelper.DARK_THEME: // The domain WebView theme is dark.
1863 // Set the icon according to the app theme.
1864 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) {
1865 webViewThemeImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.webview_dark_theme_day, null));
1867 webViewThemeImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.webview_dark_theme_night, null));
1870 // Hide the WebView theme text view.
1871 webViewThemeTextView.setVisibility(View.GONE);
1877 public void onNothingSelected(AdapterView<?> parent) {
1882 // Set the wide viewport spinner listener.
1883 wideViewportSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1885 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1886 // Update the icon and the visibility of the wide viewport text view.
1888 case DomainsDatabaseHelper.SYSTEM_DEFAULT:
1889 if (defaultWideViewport) { // Wide viewport is enabled by default.
1890 // Set the icon according to the theme.
1891 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1892 wideViewportImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.wide_viewport_enabled_night, null));
1894 wideViewportImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.wide_viewport_enabled_day, null));
1896 } else { // Wide viewport is disabled by default.
1897 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1898 wideViewportImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.wide_viewport_disabled_night, null));
1900 wideViewportImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.wide_viewport_disabled_day, null));
1904 // Show the wide viewport text view.
1905 wideViewportTextView.setVisibility(View.VISIBLE);
1908 case DomainsDatabaseHelper.ENABLED:
1909 // Set the icon according to the theme.
1910 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1911 wideViewportImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.wide_viewport_enabled_night, null));
1913 wideViewportImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.wide_viewport_enabled_day, null));
1916 // Hide the wide viewport text view.
1917 wideViewportTextView.setVisibility(View.GONE);
1920 case DomainsDatabaseHelper.DISABLED:
1921 // Set the icon according to the theme.
1922 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1923 wideViewportImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.wide_viewport_disabled_night, null));
1925 wideViewportImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.wide_viewport_disabled_day, null));
1928 // Hid ethe wide viewport text view.
1929 wideViewportTextView.setVisibility(View.GONE);
1935 public void onNothingSelected(AdapterView<?> parent) {
1940 // Set the display webpage images spinner listener.
1941 displayWebpageImagesSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1943 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1944 // Update the icon and the visibility of the display images text view.
1946 case DomainsDatabaseHelper.SYSTEM_DEFAULT:
1947 if (defaultDisplayWebpageImages) { // Display webpage images is enabled by default.
1948 // Set the icon according to the theme.
1949 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1950 displayWebpageImagesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.images_enabled_night, null));
1952 displayWebpageImagesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.images_enabled_day, null));
1954 } else { // Display webpage images is disabled by default.
1955 // Set the icon according to the theme.
1956 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1957 displayWebpageImagesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.images_disabled_night, null));
1959 displayWebpageImagesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.images_disabled_day, null));
1963 // Show the display images text view.
1964 displayImagesTextView.setVisibility(View.VISIBLE);
1967 case DomainsDatabaseHelper.ENABLED:
1968 // Set the icon according to the theme.
1969 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1970 displayWebpageImagesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.images_enabled_night, null));
1972 displayWebpageImagesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.images_enabled_day, null));
1975 // Hide the display images text view.
1976 displayImagesTextView.setVisibility(View.GONE);
1979 case DomainsDatabaseHelper.DISABLED:
1980 // Set the icon according to the theme.
1981 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1982 displayWebpageImagesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.images_disabled_night, null));
1984 displayWebpageImagesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.images_disabled_day, null));
1987 // Hide the display images text view.
1988 displayImagesTextView.setVisibility(View.GONE);
1994 public void onNothingSelected(AdapterView<?> parent) {
1999 // Set the pinned SSL certificate switch listener.
2000 pinnedSslCertificateSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
2002 if (isChecked) { // SSL certificate pinning is enabled.
2003 // Set the icon according to the theme.
2004 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
2005 pinnedSslCertificateImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.ssl_certificate_enabled_night, null));
2007 pinnedSslCertificateImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.ssl_certificate_enabled_day, null));
2010 // Update the visibility of the saved SSL certificate.
2011 if (savedSslIssuedToCNameString == null) {
2012 savedSslCardView.setVisibility(View.GONE);
2014 savedSslCardView.setVisibility(View.VISIBLE);
2017 // Update the visibility of the current website SSL certificate.
2018 if (DomainsActivity.sslIssuedToCName == null) {
2019 // Hide the SSL certificate.
2020 currentSslCardView.setVisibility(View.GONE);
2022 // Show the instruction.
2023 noCurrentWebsiteCertificateTextView.setVisibility(View.VISIBLE);
2025 // Show the SSL certificate.
2026 currentSslCardView.setVisibility(View.VISIBLE);
2028 // Hide the instruction.
2029 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
2032 // Set the status of the radio buttons.
2033 if (savedSslCardView.getVisibility() == View.VISIBLE) { // The saved SSL certificate is displayed.
2034 // Check the saved SSL certificate radio button.
2035 savedSslCertificateRadioButton.setChecked(true);
2037 // Uncheck the current website SSL certificate radio button.
2038 currentWebsiteCertificateRadioButton.setChecked(false);
2040 // Set the background of the saved SSL certificate linear layout to be transparent.
2041 savedSslCertificateLinearLayout.setBackgroundResource(R.color.transparent);
2043 // Darken the background of the current website SSL certificate linear layout according to the theme.
2044 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
2045 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2047 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2050 // Scroll to the current website SSL certificate card.
2051 savedSslCardView.getParent().requestChildFocus(savedSslCardView, savedSslCardView);
2052 } else if (currentSslCardView.getVisibility() == View.VISIBLE) { // The saved SSL certificate is hidden but the current website SSL certificate is visible.
2053 // Check the current website SSL certificate radio button.
2054 currentWebsiteCertificateRadioButton.setChecked(true);
2056 // Uncheck the saved SSL certificate radio button.
2057 savedSslCertificateRadioButton.setChecked(false);
2059 // Set the background of the current website SSL certificate linear layout to be transparent.
2060 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.transparent);
2062 // Darken the background of the saved SSL certificate linear layout according to the theme.
2063 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
2064 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2066 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2069 // Scroll to the current website SSL certificate card.
2070 currentSslCardView.getParent().requestChildFocus(currentSslCardView, currentSslCardView);
2071 } else { // Neither SSL certificate is visible.
2072 // Uncheck both radio buttons.
2073 savedSslCertificateRadioButton.setChecked(false);
2074 currentWebsiteCertificateRadioButton.setChecked(false);
2076 // Scroll to the current website SSL certificate card.
2077 noCurrentWebsiteCertificateTextView.getParent().requestChildFocus(noCurrentWebsiteCertificateTextView, noCurrentWebsiteCertificateTextView);
2079 } else { // SSL certificate pinning is disabled.
2080 // Set the icon according to the theme.
2081 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
2082 pinnedSslCertificateImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.ssl_certificate_disabled_night, null));
2084 pinnedSslCertificateImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.ssl_certificate_disabled_day, null));
2087 // Hide the SSl certificates and instructions.
2088 savedSslCardView.setVisibility(View.GONE);
2089 currentSslCardView.setVisibility(View.GONE);
2090 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
2092 // Uncheck the radio buttons.
2093 savedSslCertificateRadioButton.setChecked(false);
2094 currentWebsiteCertificateRadioButton.setChecked(false);
2098 savedSslCardView.setOnClickListener((View view) -> {
2099 // Check the saved SSL certificate radio button.
2100 savedSslCertificateRadioButton.setChecked(true);
2102 // Uncheck the current website SSL certificate radio button.
2103 currentWebsiteCertificateRadioButton.setChecked(false);
2105 // Set the background of the saved SSL certificate linear layout to be transparent.
2106 savedSslCertificateLinearLayout.setBackgroundResource(R.color.transparent);
2108 // Darken the background of the current website SSL certificate linear layout according to the theme.
2109 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
2110 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2112 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2116 savedSslCertificateRadioButton.setOnClickListener((View view) -> {
2117 // Check the saved SSL certificate radio button.
2118 savedSslCertificateRadioButton.setChecked(true);
2120 // Uncheck the current website SSL certificate radio button.
2121 currentWebsiteCertificateRadioButton.setChecked(false);
2123 // Set the background of the saved SSL certificate linear layout to be transparent.
2124 savedSslCertificateLinearLayout.setBackgroundResource(R.color.transparent);
2126 // Darken the background of the current website SSL certificate linear layout according to the theme.
2127 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
2128 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2130 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2134 currentSslCardView.setOnClickListener((View view) -> {
2135 // Check the current website SSL certificate radio button.
2136 currentWebsiteCertificateRadioButton.setChecked(true);
2138 // Uncheck the saved SSL certificate radio button.
2139 savedSslCertificateRadioButton.setChecked(false);
2141 // Set the background of the current website SSL certificate linear layout to be transparent.
2142 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.transparent);
2144 // Darken the background of the saved SSL certificate linear layout according to the theme.
2145 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
2146 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2148 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2152 currentWebsiteCertificateRadioButton.setOnClickListener((View view) -> {
2153 // Check the current website SSL certificate radio button.
2154 currentWebsiteCertificateRadioButton.setChecked(true);
2156 // Uncheck the saved SSL certificate radio button.
2157 savedSslCertificateRadioButton.setChecked(false);
2159 // Set the background of the current website SSL certificate linear layout to be transparent.
2160 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.transparent);
2162 // Darken the background of the saved SSL certificate linear layout according to the theme.
2163 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
2164 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2166 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2170 // Set the pinned IP addresses switch listener.
2171 pinnedIpAddressesSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
2173 if (isChecked) { // IP addresses pinning is enabled.
2174 // Set the icon according to the theme.
2175 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
2176 pinnedIpAddressesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.ssl_certificate_enabled_night, null));
2178 pinnedIpAddressesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.ssl_certificate_enabled_day, null));
2181 // Update the visibility of the saved IP addresses card view.
2182 if (savedIpAddresses == null) { // There are no saved IP addresses.
2183 savedIpAddressesCardView.setVisibility(View.GONE);
2184 } else { // There are saved IP addresses.
2185 savedIpAddressesCardView.setVisibility(View.VISIBLE);
2188 // Show the current IP addresses card view.
2189 currentIpAddressesCardView.setVisibility(View.VISIBLE);
2191 // Set the status of the radio buttons.
2192 if (savedIpAddressesCardView.getVisibility() == View.VISIBLE) { // The saved IP addresses are visible.
2193 // Check the saved IP addresses radio button.
2194 savedIpAddressesRadioButton.setChecked(true);
2196 // Uncheck the current IP addresses radio button.
2197 currentIpAddressesRadioButton.setChecked(false);
2199 // Set the background of the saved IP addresses linear layout to be transparent.
2200 savedSslCertificateLinearLayout.setBackgroundResource(R.color.transparent);
2202 // Darken the background of the current IP addresses linear layout according to the theme.
2203 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
2204 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2206 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2208 } else { // The saved IP addresses are not visible.
2209 // Check the current IP addresses radio button.
2210 currentIpAddressesRadioButton.setChecked(true);
2212 // Uncheck the saved IP addresses radio button.
2213 savedIpAddressesRadioButton.setChecked(false);
2215 // Set the background of the current IP addresses linear layout to be transparent.
2216 currentIpAddressesLinearLayout.setBackgroundResource(R.color.transparent);
2218 // Darken the background of the saved IP addresses linear layout according to the theme.
2219 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
2220 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2222 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2226 // Scroll to the bottom of the card views.
2227 currentIpAddressesCardView.getParent().requestChildFocus(currentIpAddressesCardView, currentIpAddressesCardView);
2228 } else { // IP addresses pinning is disabled.
2229 // Set the icon according to the theme.
2230 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
2231 pinnedIpAddressesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.ssl_certificate_disabled_night, null));
2233 pinnedIpAddressesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.ssl_certificate_disabled_day, null));
2236 // Hide the IP addresses card views.
2237 savedIpAddressesCardView.setVisibility(View.GONE);
2238 currentIpAddressesCardView.setVisibility(View.GONE);
2240 // Uncheck the radio buttons.
2241 savedIpAddressesRadioButton.setChecked(false);
2242 currentIpAddressesRadioButton.setChecked(false);
2246 savedIpAddressesCardView.setOnClickListener((View view) -> {
2247 // Check the saved IP addresses radio button.
2248 savedIpAddressesRadioButton.setChecked(true);
2250 // Uncheck the current website IP addresses radio button.
2251 currentIpAddressesRadioButton.setChecked(false);
2253 // Set the background of the saved IP addresses linear layout to be transparent.
2254 savedIpAddressesLinearLayout.setBackgroundResource(R.color.transparent);
2256 // Darken the background of the current IP addresses linear layout according to the theme.
2257 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
2258 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2260 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2264 savedIpAddressesRadioButton.setOnClickListener((View view) -> {
2265 // Check the saved IP addresses radio button.
2266 savedIpAddressesRadioButton.setChecked(true);
2268 // Uncheck the current website IP addresses radio button.
2269 currentIpAddressesRadioButton.setChecked(false);
2271 // Set the background of the saved IP addresses linear layout to be transparent.
2272 savedIpAddressesLinearLayout.setBackgroundResource(R.color.transparent);
2274 // Darken the background of the current IP addresses linear layout according to the theme.
2275 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
2276 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2278 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2282 currentIpAddressesCardView.setOnClickListener((View view) -> {
2283 // Check the current IP addresses radio button.
2284 currentIpAddressesRadioButton.setChecked(true);
2286 // Uncheck the saved IP addresses radio button.
2287 savedIpAddressesRadioButton.setChecked(false);
2289 // Set the background of the current IP addresses linear layout to be transparent.
2290 currentIpAddressesLinearLayout.setBackgroundResource(R.color.transparent);
2292 // Darken the background of the saved IP addresses linear layout according to the theme.
2293 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
2294 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2296 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2300 currentIpAddressesRadioButton.setOnClickListener((View view) -> {
2301 // Check the current IP addresses radio button.
2302 currentIpAddressesRadioButton.setChecked(true);
2304 // Uncheck the saved IP addresses radio button.
2305 savedIpAddressesRadioButton.setChecked(false);
2307 // Set the background of the current IP addresses linear layout to be transparent.
2308 currentIpAddressesLinearLayout.setBackgroundResource(R.color.transparent);
2310 // Darken the background of the saved IP addresses linear layout according to the theme.
2311 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
2312 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2314 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2318 // Set the scroll Y.
2319 domainSettingsScrollView.post(() -> domainSettingsScrollView.setScrollY(scrollY));
2321 // Return the domain settings view.
2322 return domainSettingsView;
2325 private boolean checkDomainNameAgainstCertificate(String domainName, String certificateCommonName) {
2326 // Initialize `domainNamesMatch`.
2327 boolean domainNamesMatch = false;
2329 // Check various wildcard permutations if `domainName` and `certificateCommonName` are not empty.
2330 // `noinspection ConstantCondition` removes Android Studio's incorrect lint warning that `domainName` can never be `null`.
2331 if ((domainName != null) && (certificateCommonName != null)) {
2332 // Check if the domains match.
2333 if (domainName.equals(certificateCommonName)) {
2334 domainNamesMatch = true;
2337 // If `domainName` starts with a wildcard, check the base domain against all the subdomains of `certificateCommonName`.
2338 if (!domainNamesMatch && domainName.startsWith("*.") && (domainName.length() > 2)) {
2339 // Remove the initial `*.`.
2340 String baseDomainName = domainName.substring(2);
2342 // Setup a copy of `certificateCommonName` to test subdomains.
2343 String certificateCommonNameSubdomain = certificateCommonName;
2345 // Check all the subdomains in `certificateCommonNameSubdomain` against `baseDomainName`.
2346 while (!domainNamesMatch && certificateCommonNameSubdomain.contains(".")) { // Stop checking if we know that `domainNamesMatch` is `true` or if we run out of `.`.
2347 // Test the `certificateCommonNameSubdomain` against `baseDomainName`.
2348 if (certificateCommonNameSubdomain.equals(baseDomainName)) {
2349 domainNamesMatch = true;
2352 // Strip out the lowest subdomain of `certificateCommonNameSubdomain`.
2354 certificateCommonNameSubdomain = certificateCommonNameSubdomain.substring(certificateCommonNameSubdomain.indexOf(".") + 1);
2355 } catch (IndexOutOfBoundsException e) { // `certificateCommonNameSubdomain` ends with `.`.
2356 certificateCommonNameSubdomain = "";
2361 // If `certificateCommonName` starts with a wildcard, check the base common name against all the subdomains of `domainName`.
2362 if (!domainNamesMatch && certificateCommonName.startsWith("*.") && (certificateCommonName.length() > 2)) {
2363 // Remove the initial `*.`.
2364 String baseCertificateCommonName = certificateCommonName.substring(2);
2366 // Setup a copy of `domainName` to test subdomains.
2367 String domainNameSubdomain = domainName;
2369 // Check all the subdomains in `domainNameSubdomain` against `baseCertificateCommonName`.
2370 while (!domainNamesMatch && domainNameSubdomain.contains(".") && (domainNameSubdomain.length() > 2)) {
2371 // Test the `domainNameSubdomain` against `baseCertificateCommonName`.
2372 if (domainNameSubdomain.equals(baseCertificateCommonName)) {
2373 domainNamesMatch = true;
2376 // Strip out the lowest subdomain of `domainNameSubdomain`.
2378 domainNameSubdomain = domainNameSubdomain.substring(domainNameSubdomain.indexOf(".") + 1);
2379 } catch (IndexOutOfBoundsException e) { // `domainNameSubdomain` ends with `.`.
2380 domainNameSubdomain = "";
2385 // If both names start with a wildcard, check if the root of one contains the root of the other.
2386 if (!domainNamesMatch && domainName.startsWith("*.") && (domainName.length() > 2) && certificateCommonName.startsWith("*.") && (certificateCommonName.length() > 2)) {
2387 // Remove the wildcards.
2388 String rootDomainName = domainName.substring(2);
2389 String rootCertificateCommonName = certificateCommonName.substring(2);
2391 // Check if one name ends with the contents of the other. If so, there will be overlap in the their wildcard subdomains.
2392 if (rootDomainName.endsWith(rootCertificateCommonName) || rootCertificateCommonName.endsWith(rootDomainName)) {
2393 domainNamesMatch = true;
2398 return domainNamesMatch;