2 * Copyright © 2017-2022 Soren Stoutner <soren@stoutner.com>.
4 * This file is part of Privacy Browser Android <https://www.stoutner.com/privacy-browser-android>.
6 * Privacy Browser Android 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 Android 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 Android. 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 cookiesImageView = domainSettingsView.findViewById(R.id.cookies_imageview);
124 SwitchCompat cookiesSwitch = domainSettingsView.findViewById(R.id.cookies_switch);
125 ImageView domStorageImageView = domainSettingsView.findViewById(R.id.dom_storage_imageview);
126 SwitchCompat domStorageSwitch = domainSettingsView.findViewById(R.id.dom_storage_switch);
127 ImageView formDataImageView = domainSettingsView.findViewById(R.id.form_data_imageview); // The form data views can be remove once the minimum API >= 26.
128 SwitchCompat formDataSwitch = domainSettingsView.findViewById(R.id.form_data_switch); // The form data views can be remove once the minimum API >= 26.
129 ImageView easyListImageView = domainSettingsView.findViewById(R.id.easylist_imageview);
130 SwitchCompat easyListSwitch = domainSettingsView.findViewById(R.id.easylist_switch);
131 ImageView easyPrivacyImageView = domainSettingsView.findViewById(R.id.easyprivacy_imageview);
132 SwitchCompat easyPrivacySwitch = domainSettingsView.findViewById(R.id.easyprivacy_switch);
133 ImageView fanboysAnnoyanceListImageView = domainSettingsView.findViewById(R.id.fanboys_annoyance_list_imageview);
134 SwitchCompat fanboysAnnoyanceListSwitch = domainSettingsView.findViewById(R.id.fanboys_annoyance_list_switch);
135 ImageView fanboysSocialBlockingListImageView = domainSettingsView.findViewById(R.id.fanboys_social_blocking_list_imageview);
136 SwitchCompat fanboysSocialBlockingListSwitch = domainSettingsView.findViewById(R.id.fanboys_social_blocking_list_switch);
137 ImageView ultraListImageView = domainSettingsView.findViewById(R.id.ultralist_imageview);
138 SwitchCompat ultraListSwitch = domainSettingsView.findViewById(R.id.ultralist_switch);
139 ImageView ultraPrivacyImageView = domainSettingsView.findViewById(R.id.ultraprivacy_imageview);
140 SwitchCompat ultraPrivacySwitch = domainSettingsView.findViewById(R.id.ultraprivacy_switch);
141 ImageView blockAllThirdPartyRequestsImageView = domainSettingsView.findViewById(R.id.block_all_third_party_requests_imageview);
142 SwitchCompat blockAllThirdPartyRequestsSwitch = domainSettingsView.findViewById(R.id.block_all_third_party_requests_switch);
143 Spinner userAgentSpinner = domainSettingsView.findViewById(R.id.user_agent_spinner);
144 TextView userAgentTextView = domainSettingsView.findViewById(R.id.user_agent_textview);
145 EditText customUserAgentEditText = domainSettingsView.findViewById(R.id.custom_user_agent_edittext);
146 Spinner fontSizeSpinner = domainSettingsView.findViewById(R.id.font_size_spinner);
147 TextView defaultFontSizeTextView = domainSettingsView.findViewById(R.id.default_font_size_textview);
148 EditText customFontSizeEditText = domainSettingsView.findViewById(R.id.custom_font_size_edittext);
149 ImageView swipeToRefreshImageView = domainSettingsView.findViewById(R.id.swipe_to_refresh_imageview);
150 Spinner swipeToRefreshSpinner = domainSettingsView.findViewById(R.id.swipe_to_refresh_spinner);
151 TextView swipeToRefreshTextView = domainSettingsView.findViewById(R.id.swipe_to_refresh_textview);
152 ImageView webViewThemeImageView = domainSettingsView.findViewById(R.id.webview_theme_imageview);
153 Spinner webViewThemeSpinner = domainSettingsView.findViewById(R.id.webview_theme_spinner);
154 TextView webViewThemeTextView = domainSettingsView.findViewById(R.id.webview_theme_textview);
155 ImageView wideViewportImageView = domainSettingsView.findViewById(R.id.wide_viewport_imageview);
156 Spinner wideViewportSpinner = domainSettingsView.findViewById(R.id.wide_viewport_spinner);
157 TextView wideViewportTextView = domainSettingsView.findViewById(R.id.wide_viewport_textview);
158 ImageView displayWebpageImagesImageView = domainSettingsView.findViewById(R.id.display_webpage_images_imageview);
159 Spinner displayWebpageImagesSpinner = domainSettingsView.findViewById(R.id.display_webpage_images_spinner);
160 TextView displayImagesTextView = domainSettingsView.findViewById(R.id.display_webpage_images_textview);
161 ImageView pinnedSslCertificateImageView = domainSettingsView.findViewById(R.id.pinned_ssl_certificate_imageview);
162 SwitchCompat pinnedSslCertificateSwitch = domainSettingsView.findViewById(R.id.pinned_ssl_certificate_switch);
163 CardView savedSslCardView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_cardview);
164 LinearLayout savedSslCertificateLinearLayout = domainSettingsView.findViewById(R.id.saved_ssl_certificate_linearlayout);
165 RadioButton savedSslCertificateRadioButton = domainSettingsView.findViewById(R.id.saved_ssl_certificate_radiobutton);
166 TextView savedSslIssuedToCNameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_to_cname);
167 TextView savedSslIssuedToONameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_to_oname);
168 TextView savedSslIssuedToUNameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_to_uname);
169 TextView savedSslIssuedByCNameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_by_cname);
170 TextView savedSslIssuedByONameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_by_oname);
171 TextView savedSslIssuedByUNameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_by_uname);
172 TextView savedSslStartDateTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_start_date);
173 TextView savedSslEndDateTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_end_date);
174 CardView currentSslCardView = domainSettingsView.findViewById(R.id.current_website_certificate_cardview);
175 LinearLayout currentWebsiteCertificateLinearLayout = domainSettingsView.findViewById(R.id.current_website_certificate_linearlayout);
176 RadioButton currentWebsiteCertificateRadioButton = domainSettingsView.findViewById(R.id.current_website_certificate_radiobutton);
177 TextView currentSslIssuedToCNameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_to_cname);
178 TextView currentSslIssuedToONameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_to_oname);
179 TextView currentSslIssuedToUNameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_to_uname);
180 TextView currentSslIssuedByCNameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_by_cname);
181 TextView currentSslIssuedByONameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_by_oname);
182 TextView currentSslIssuedByUNameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_by_uname);
183 TextView currentSslStartDateTextView = domainSettingsView.findViewById(R.id.current_website_certificate_start_date);
184 TextView currentSslEndDateTextView = domainSettingsView.findViewById(R.id.current_website_certificate_end_date);
185 TextView noCurrentWebsiteCertificateTextView = domainSettingsView.findViewById(R.id.no_current_website_certificate);
186 ImageView pinnedIpAddressesImageView = domainSettingsView.findViewById(R.id.pinned_ip_addresses_imageview);
187 SwitchCompat pinnedIpAddressesSwitch = domainSettingsView.findViewById(R.id.pinned_ip_addresses_switch);
188 CardView savedIpAddressesCardView = domainSettingsView.findViewById(R.id.saved_ip_addresses_cardview);
189 LinearLayout savedIpAddressesLinearLayout = domainSettingsView.findViewById(R.id.saved_ip_addresses_linearlayout);
190 RadioButton savedIpAddressesRadioButton = domainSettingsView.findViewById(R.id.saved_ip_addresses_radiobutton);
191 TextView savedIpAddressesTextView = domainSettingsView.findViewById(R.id.saved_ip_addresses_textview);
192 CardView currentIpAddressesCardView = domainSettingsView.findViewById(R.id.current_ip_addresses_cardview);
193 LinearLayout currentIpAddressesLinearLayout = domainSettingsView.findViewById(R.id.current_ip_addresses_linearlayout);
194 RadioButton currentIpAddressesRadioButton = domainSettingsView.findViewById(R.id.current_ip_addresses_radiobutton);
195 TextView currentIpAddressesTextView = domainSettingsView.findViewById(R.id.current_ip_addresses_textview);
197 // Setup the pinned labels.
198 String cNameLabel = getString(R.string.common_name) + " ";
199 String oNameLabel = getString(R.string.organization) + " ";
200 String uNameLabel = getString(R.string.organizational_unit) + " ";
201 String startDateLabel = getString(R.string.start_date) + " ";
202 String endDateLabel = getString(R.string.end_date) + " ";
204 // Initialize the database handler. The `0` specifies the database version, but that is ignored and set instead using a constant in `DomainsDatabaseHelper`.
205 DomainsDatabaseHelper domainsDatabaseHelper = new DomainsDatabaseHelper(context, null, null, 0);
207 // Get the database cursor for this ID and move it to the first row.
208 Cursor domainCursor = domainsDatabaseHelper.getCursorForId(databaseId);
209 domainCursor.moveToFirst();
211 // Save the cursor entries as variables.
212 String domainNameString = domainCursor.getString(domainCursor.getColumnIndexOrThrow(DomainsDatabaseHelper.DOMAIN_NAME));
213 int javaScriptInt = domainCursor.getInt(domainCursor.getColumnIndexOrThrow(DomainsDatabaseHelper.ENABLE_JAVASCRIPT));
214 int cookiesInt = domainCursor.getInt(domainCursor.getColumnIndexOrThrow(DomainsDatabaseHelper.COOKIES));
215 int domStorageInt = domainCursor.getInt(domainCursor.getColumnIndexOrThrow(DomainsDatabaseHelper.ENABLE_DOM_STORAGE));
216 int formDataInt = domainCursor.getInt(domainCursor.getColumnIndexOrThrow(DomainsDatabaseHelper.ENABLE_FORM_DATA)); // Form data can be remove once the minimum API >= 26.
217 int easyListInt = domainCursor.getInt(domainCursor.getColumnIndexOrThrow(DomainsDatabaseHelper.ENABLE_EASYLIST));
218 int easyPrivacyInt = domainCursor.getInt(domainCursor.getColumnIndexOrThrow(DomainsDatabaseHelper.ENABLE_EASYPRIVACY));
219 int fanboysAnnoyanceListInt = domainCursor.getInt(domainCursor.getColumnIndexOrThrow(DomainsDatabaseHelper.ENABLE_FANBOYS_ANNOYANCE_LIST));
220 int fanboysSocialBlockingListInt = domainCursor.getInt(domainCursor.getColumnIndexOrThrow(DomainsDatabaseHelper.ENABLE_FANBOYS_SOCIAL_BLOCKING_LIST));
221 int ultraListInt = domainCursor.getInt(domainCursor.getColumnIndexOrThrow(DomainsDatabaseHelper.ULTRALIST));
222 int ultraPrivacyInt = domainCursor.getInt(domainCursor.getColumnIndexOrThrow(DomainsDatabaseHelper.ENABLE_ULTRAPRIVACY));
223 int blockAllThirdPartyRequestsInt = domainCursor.getInt(domainCursor.getColumnIndexOrThrow(DomainsDatabaseHelper.BLOCK_ALL_THIRD_PARTY_REQUESTS));
224 String currentUserAgentName = domainCursor.getString(domainCursor.getColumnIndexOrThrow(DomainsDatabaseHelper.USER_AGENT));
225 int fontSizeInt = domainCursor.getInt(domainCursor.getColumnIndexOrThrow(DomainsDatabaseHelper.FONT_SIZE));
226 int swipeToRefreshInt = domainCursor.getInt(domainCursor.getColumnIndexOrThrow(DomainsDatabaseHelper.SWIPE_TO_REFRESH));
227 int webViewThemeInt = domainCursor.getInt(domainCursor.getColumnIndexOrThrow(DomainsDatabaseHelper.WEBVIEW_THEME));
228 int wideViewportInt = domainCursor.getInt(domainCursor.getColumnIndexOrThrow(DomainsDatabaseHelper.WIDE_VIEWPORT));
229 int displayImagesInt = domainCursor.getInt(domainCursor.getColumnIndexOrThrow(DomainsDatabaseHelper.DISPLAY_IMAGES));
230 int pinnedSslCertificateInt = domainCursor.getInt(domainCursor.getColumnIndexOrThrow(DomainsDatabaseHelper.PINNED_SSL_CERTIFICATE));
231 String savedSslIssuedToCNameString = domainCursor.getString(domainCursor.getColumnIndexOrThrow(DomainsDatabaseHelper.SSL_ISSUED_TO_COMMON_NAME));
232 String savedSslIssuedToONameString = domainCursor.getString(domainCursor.getColumnIndexOrThrow(DomainsDatabaseHelper.SSL_ISSUED_TO_ORGANIZATION));
233 String savedSslIssuedToUNameString = domainCursor.getString(domainCursor.getColumnIndexOrThrow(DomainsDatabaseHelper.SSL_ISSUED_TO_ORGANIZATIONAL_UNIT));
234 String savedSslIssuedByCNameString = domainCursor.getString(domainCursor.getColumnIndexOrThrow(DomainsDatabaseHelper.SSL_ISSUED_BY_COMMON_NAME));
235 String savedSslIssuedByONameString = domainCursor.getString(domainCursor.getColumnIndexOrThrow(DomainsDatabaseHelper.SSL_ISSUED_BY_ORGANIZATION));
236 String savedSslIssuedByUNameString = domainCursor.getString(domainCursor.getColumnIndexOrThrow(DomainsDatabaseHelper.SSL_ISSUED_BY_ORGANIZATIONAL_UNIT));
237 int pinnedIpAddressesInt = domainCursor.getInt(domainCursor.getColumnIndexOrThrow(DomainsDatabaseHelper.PINNED_IP_ADDRESSES));
238 String savedIpAddresses = domainCursor.getString(domainCursor.getColumnIndexOrThrow(DomainsDatabaseHelper.IP_ADDRESSES));
240 // Initialize the saved SSL certificate date variables.
241 Date savedSslStartDate = null;
242 Date savedSslEndDate = null;
244 // Only get the saved SSL certificate dates from the cursor if they are not set to `0`.
245 if (domainCursor.getLong(domainCursor.getColumnIndexOrThrow(DomainsDatabaseHelper.SSL_START_DATE)) != 0) {
246 savedSslStartDate = new Date(domainCursor.getLong(domainCursor.getColumnIndexOrThrow(DomainsDatabaseHelper.SSL_START_DATE)));
249 if (domainCursor.getLong(domainCursor.getColumnIndexOrThrow(DomainsDatabaseHelper.SSL_END_DATE)) != 0) {
250 savedSslEndDate = new Date(domainCursor.getLong(domainCursor.getColumnIndexOrThrow(DomainsDatabaseHelper.SSL_END_DATE)));
253 // Create array adapters for the spinners.
254 ArrayAdapter<CharSequence> translatedUserAgentArrayAdapter = ArrayAdapter.createFromResource(context, R.array.translated_domain_settings_user_agent_names, R.layout.spinner_item);
255 ArrayAdapter<CharSequence> fontSizeArrayAdapter = ArrayAdapter.createFromResource(context, R.array.font_size_array, R.layout.spinner_item);
256 ArrayAdapter<CharSequence> swipeToRefreshArrayAdapter = ArrayAdapter.createFromResource(context, R.array.swipe_to_refresh_array, R.layout.spinner_item);
257 ArrayAdapter<CharSequence> webViewThemeArrayAdapter = ArrayAdapter.createFromResource(context, R.array.webview_theme_array, R.layout.spinner_item);
258 ArrayAdapter<CharSequence> wideViewportArrayAdapter = ArrayAdapter.createFromResource(context, R.array.wide_viewport_array, R.layout.spinner_item);
259 ArrayAdapter<CharSequence> displayImagesArrayAdapter = ArrayAdapter.createFromResource(context, R.array.display_webpage_images_array, R.layout.spinner_item);
261 // Set the drop down view resource on the spinners.
262 translatedUserAgentArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items);
263 fontSizeArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items);
264 swipeToRefreshArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items);
265 webViewThemeArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items);
266 wideViewportArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items);
267 displayImagesArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items);
269 // Set the array adapters for the spinners.
270 userAgentSpinner.setAdapter(translatedUserAgentArrayAdapter);
271 fontSizeSpinner.setAdapter(fontSizeArrayAdapter);
272 swipeToRefreshSpinner.setAdapter(swipeToRefreshArrayAdapter);
273 webViewThemeSpinner.setAdapter(webViewThemeArrayAdapter);
274 wideViewportSpinner.setAdapter(wideViewportArrayAdapter);
275 displayWebpageImagesSpinner.setAdapter(displayImagesArrayAdapter);
277 // Create a spannable string builder for each TextView that needs multiple colors of text.
278 SpannableStringBuilder savedSslIssuedToCNameStringBuilder = new SpannableStringBuilder(cNameLabel + savedSslIssuedToCNameString);
279 SpannableStringBuilder savedSslIssuedToONameStringBuilder = new SpannableStringBuilder(oNameLabel + savedSslIssuedToONameString);
280 SpannableStringBuilder savedSslIssuedToUNameStringBuilder = new SpannableStringBuilder(uNameLabel + savedSslIssuedToUNameString);
281 SpannableStringBuilder savedSslIssuedByCNameStringBuilder = new SpannableStringBuilder(cNameLabel + savedSslIssuedByCNameString);
282 SpannableStringBuilder savedSslIssuedByONameStringBuilder = new SpannableStringBuilder(oNameLabel + savedSslIssuedByONameString);
283 SpannableStringBuilder savedSslIssuedByUNameStringBuilder = new SpannableStringBuilder(uNameLabel + savedSslIssuedByUNameString);
285 // Initialize the spannable string builders for the saved SSL certificate dates.
286 SpannableStringBuilder savedSslStartDateStringBuilder;
287 SpannableStringBuilder savedSslEndDateStringBuilder;
289 // Leave the SSL certificate dates empty if they are `null`.
290 if (savedSslStartDate == null) {
291 savedSslStartDateStringBuilder = new SpannableStringBuilder(startDateLabel);
293 savedSslStartDateStringBuilder = new SpannableStringBuilder(startDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(savedSslStartDate));
296 if (savedSslEndDate == null) {
297 savedSslEndDateStringBuilder = new SpannableStringBuilder(endDateLabel);
299 savedSslEndDateStringBuilder = new SpannableStringBuilder(endDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(savedSslEndDate));
302 // Create the color spans.
303 final ForegroundColorSpan blueColorSpan = new ForegroundColorSpan(context.getColor(R.color.blue_text));
304 final ForegroundColorSpan redColorSpan = new ForegroundColorSpan(context.getColor(R.color.red_text));
306 // Set the domain name from the the database cursor.
307 domainNameEditText.setText(domainNameString);
309 // Update the certificates' `Common Name` color when the domain name text changes.
310 domainNameEditText.addTextChangedListener(new TextWatcher() {
312 public void beforeTextChanged(CharSequence s, int start, int count, int after) {
317 public void onTextChanged(CharSequence s, int start, int before, int count) {
322 public void afterTextChanged(Editable s) {
323 // Get the new domain name.
324 String newDomainName = domainNameEditText.getText().toString();
326 // Check the saved SSL certificate against the new domain name.
327 boolean savedSslMatchesNewDomainName = checkDomainNameAgainstCertificate(newDomainName, savedSslIssuedToCNameString);
329 // Create a `SpannableStringBuilder` for the saved certificate `Common Name`.
330 SpannableStringBuilder savedSslCNameStringBuilder = new SpannableStringBuilder(cNameLabel + savedSslIssuedToCNameString);
332 // Format the saved certificate `Common Name` color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
333 if (savedSslMatchesNewDomainName) {
334 savedSslCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), savedSslCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
336 savedSslCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), savedSslCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
339 // Update the saved SSL issued to CName text view.
340 savedSslIssuedToCNameTextView.setText(savedSslCNameStringBuilder);
342 // Update the current website certificate if it exists.
343 if (DomainsActivity.sslIssuedToCName != null) {
344 // Check the current website certificate against the new domain name.
345 boolean currentSslMatchesNewDomainName = checkDomainNameAgainstCertificate(newDomainName, DomainsActivity.sslIssuedToCName);
347 // Create a `SpannableStringBuilder` for the current website certificate `Common Name`.
348 SpannableStringBuilder currentSslCNameStringBuilder = new SpannableStringBuilder(cNameLabel + DomainsActivity.sslIssuedToCName);
350 // Format the current certificate `Common Name` color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
351 if (currentSslMatchesNewDomainName) {
352 currentSslCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), currentSslCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
354 currentSslCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), currentSslCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
357 // Update the current SSL issued to CName text view.
358 currentSslIssuedToCNameTextView.setText(currentSslCNameStringBuilder);
363 // Set the JavaScript switch status.
364 if (javaScriptInt == 1) { // JavaScript is enabled.
365 javaScriptSwitch.setChecked(true);
366 javaScriptImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.javascript_enabled, null));
367 } else { // JavaScript is disabled.
368 javaScriptSwitch.setChecked(false);
369 javaScriptImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.privacy_mode, null));
372 // Set the cookies switch status. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
373 // Doing this makes no sense until it can also be done with the preferences.
374 if (cookiesInt == 1) { // Cookies are enabled.
375 // Turn the switch on.
376 cookiesSwitch.setChecked(true);
379 cookiesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.cookies_enabled, null));
380 } else { // Cookies are disabled.
381 // Turn the switch off
382 cookiesSwitch.setChecked(false);
385 cookiesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.cookies_disabled, null));
388 // Only enable DOM storage if JavaScript is enabled.
389 if (javaScriptInt == 1) { // JavaScript is enabled.
390 // Enable the DOM storage switch.
391 domStorageSwitch.setEnabled(true);
393 // Set the DOM storage status. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
394 // Doing this makes no sense until it can also be done with the preferences.
395 if (domStorageInt == 1) { // Both JavaScript and DOM storage are enabled.
396 domStorageSwitch.setChecked(true);
397 domStorageImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.dom_storage_enabled, null));
398 } else { // JavaScript is enabled but DOM storage is disabled.
399 // Set the DOM storage switch to off.
400 domStorageSwitch.setChecked(false);
403 domStorageImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.dom_storage_disabled, null));
405 } else { // JavaScript is disabled.
406 // Disable the DOM storage switch.
407 domStorageSwitch.setEnabled(false);
409 // Set the checked status of DOM storage.
410 domStorageSwitch.setChecked(domStorageInt == 1);
413 domStorageImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.dom_storage_ghosted, null));
416 // Set the form data visibility. Form data can be removed once the minimum API >= 26.
417 if (Build.VERSION.SDK_INT >= 26) { // Form data no longer applies to newer versions of Android.
418 // Hide the form data image view and switch.
419 formDataImageView.setVisibility(View.GONE);
420 formDataSwitch.setVisibility(View.GONE);
421 } else { // Form data should be displayed because this is an older version of Android.
422 if (formDataInt == 1) { // Form data is on.
423 // Turn the form data switch on.
424 formDataSwitch.setChecked(true);
426 // Set the form data icon.
427 formDataImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.form_data_enabled, null));
428 } else { // Form data is off.
429 // Turn the form data switch to off.
430 formDataSwitch.setChecked(false);
432 // Set the icon. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
433 // Doing this makes no sense until it can also be done with the preferences.
434 formDataImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.form_data_disabled, null));
438 // Set the EasyList status. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
439 // Doing this makes no sense until it can also be done with the preferences.
440 if (easyListInt == 1) { // EasyList is on.
441 // Turn the switch on.
442 easyListSwitch.setChecked(true);
445 easyListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_ads_enabled, null));
446 } else { // EasyList is off.
447 // Turn the switch off.
448 easyListSwitch.setChecked(false);
451 easyListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_ads_disabled, null));
454 // Set the EasyPrivacy status. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
455 // Doing this makes no sense until it can also be done with the preferences.
456 if (easyPrivacyInt == 1) { // EasyPrivacy is on.
457 // Turn the switch on.
458 easyPrivacySwitch.setChecked(true);
461 easyPrivacyImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_tracking_enabled, null));
462 } else { // EasyPrivacy is off.
463 // Turn the switch off.
464 easyPrivacySwitch.setChecked(false);
467 easyPrivacyImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_tracking_disabled, null));
470 // 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.
471 // Doing this makes no sense until it can also be done with the preferences.
472 if (fanboysAnnoyanceListInt == 1) { // Fanboy's Annoyance List is on.
473 // Turn the switch on.
474 fanboysAnnoyanceListSwitch.setChecked(true);
477 fanboysAnnoyanceListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.social_media_enabled, null));
478 } else { // Fanboy's Annoyance List is off.
479 // Turn the switch off.
480 fanboysAnnoyanceListSwitch.setChecked(false);
483 fanboysAnnoyanceListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.social_media_disabled, null));
486 // Only enable Fanboy's Social Blocking List if Fanboy's Annoyance List is off.
487 if (fanboysAnnoyanceListInt == 0) { // Fanboy's Annoyance List is on.
488 // Enable Fanboy's Social Blocking List switch.
489 fanboysSocialBlockingListSwitch.setEnabled(true);
491 // 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.
492 // Doing this makes no sense until it can also be done with the preferences.
493 if (fanboysSocialBlockingListInt == 1) { // Fanboy's Social Blocking List is on.
494 // Turn on Fanboy's Social Blocking List switch.
495 fanboysSocialBlockingListSwitch.setChecked(true);
498 fanboysSocialBlockingListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.social_media_enabled, null));
499 } else { // Fanboy's Social Blocking List is off.
500 // Turn off Fanboy's Social Blocking List switch.
501 fanboysSocialBlockingListSwitch.setChecked(false);
504 fanboysSocialBlockingListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.social_media_disabled, null));
506 } else { // Fanboy's Annoyance List is on.
507 // Disable Fanboy's Social Blocking List switch.
508 fanboysSocialBlockingListSwitch.setEnabled(false);
510 // Set the status of Fanboy's Social Blocking List.
511 fanboysSocialBlockingListSwitch.setChecked(fanboysSocialBlockingListInt == 1);
514 fanboysSocialBlockingListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.social_media_ghosted, null));
517 // Set the UltraList status. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
518 // Doing this makes no sense until it can also be done with the preferences.
519 if (ultraListInt == 1) { // UltraList is on.
520 // Turn the switch on.
521 ultraListSwitch.setChecked(true);
524 ultraListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_ads_enabled, null));
525 } else { // UltraList is off.
526 // Turn the switch off.
527 ultraListSwitch.setChecked(false);
530 ultraListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_ads_disabled, null));
533 // Set the UltraPrivacy status. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
534 // Doing this makes no sense until it can also be done with the preferences.
535 if (ultraPrivacyInt == 1) { // UltraPrivacy is on.
536 // Turn the switch on.
537 ultraPrivacySwitch.setChecked(true);
540 ultraPrivacyImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_tracking_enabled, null));
541 } else { // EasyPrivacy is off.
542 // Turn the switch off.
543 ultraPrivacySwitch.setChecked(false);
546 ultraPrivacyImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_tracking_disabled, null));
549 // 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.
550 // Doing this makes no sense until it can also be done with the preferences.
551 if (blockAllThirdPartyRequestsInt == 1) { // Blocking all third-party requests is on.
552 // Turn the switch on.
553 blockAllThirdPartyRequestsSwitch.setChecked(true);
556 blockAllThirdPartyRequestsImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_all_third_party_requests_enabled, null));
557 } else { // Blocking all third-party requests is off.
558 // Turn the switch off.
559 blockAllThirdPartyRequestsSwitch.setChecked(false);
562 blockAllThirdPartyRequestsImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_all_third_party_requests_disabled, null));
565 // Inflated a WebView to get the default user agent.
566 // `@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.
567 @SuppressLint("InflateParams") View bareWebViewLayout = inflater.inflate(R.layout.bare_webview, null, false);
568 WebView bareWebView = bareWebViewLayout.findViewById(R.id.bare_webview);
569 final String webViewDefaultUserAgentString = bareWebView.getSettings().getUserAgentString();
571 // Get a handle for the user agent array adapter. This array does not contain the `System default` entry.
572 ArrayAdapter<CharSequence> userAgentNamesArray = ArrayAdapter.createFromResource(context, R.array.user_agent_names, R.layout.spinner_item);
574 // Get the positions of the user agent and the default user agent.
575 int userAgentArrayPosition = userAgentNamesArray.getPosition(currentUserAgentName);
576 int defaultUserAgentArrayPosition = userAgentNamesArray.getPosition(defaultUserAgentName);
578 // Get a handle for the user agent data array. This array does not contain the `System default` entry.
579 String[] userAgentDataArray = resources.getStringArray(R.array.user_agent_data);
581 // Set the user agent text.
582 if (currentUserAgentName.equals(getString(R.string.system_default_user_agent))) { // Use the system default user agent.
583 // Set the user agent according to the system default.
584 switch (defaultUserAgentArrayPosition) {
585 case MainWebViewActivity.UNRECOGNIZED_USER_AGENT: // The default user agent name is not on the canonical list.
586 // This is probably because it was set in an older version of Privacy Browser before the switch to persistent user agent names.
587 userAgentTextView.setText(defaultUserAgentName);
590 case MainWebViewActivity.SETTINGS_WEBVIEW_DEFAULT_USER_AGENT:
591 // Display the `WebView` default user agent.
592 userAgentTextView.setText(webViewDefaultUserAgentString);
595 case MainWebViewActivity.SETTINGS_CUSTOM_USER_AGENT:
596 // Display the custom user agent.
597 userAgentTextView.setText(defaultCustomUserAgentString);
601 // Get the user agent string from the user agent data array.
602 userAgentTextView.setText(userAgentDataArray[defaultUserAgentArrayPosition]);
604 } else if (userAgentArrayPosition == MainWebViewActivity.UNRECOGNIZED_USER_AGENT) { // A custom user agent is stored in the current user agent name.
605 // Set the user agent spinner to `Custom user agent`.
606 userAgentSpinner.setSelection(MainWebViewActivity.DOMAINS_CUSTOM_USER_AGENT);
608 // Hide the user agent TextView.
609 userAgentTextView.setVisibility(View.GONE);
611 // Show the custom user agent EditText and set the current user agent name as the text.
612 customUserAgentEditText.setVisibility(View.VISIBLE);
613 customUserAgentEditText.setText(currentUserAgentName);
614 } else { // The user agent name contains one of the canonical user agents.
615 // 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.
616 userAgentSpinner.setSelection(userAgentArrayPosition + 1);
618 // Show the user agent TextView.
619 userAgentTextView.setVisibility(View.VISIBLE);
621 // Hide the custom user agent EditText.
622 customUserAgentEditText.setVisibility(View.GONE);
624 // Set the user agent text.
625 if (userAgentArrayPosition == MainWebViewActivity.DOMAINS_WEBVIEW_DEFAULT_USER_AGENT) { // The WebView default user agent is selected.
626 // Display the WebView default user agent.
627 userAgentTextView.setText(webViewDefaultUserAgentString);
628 } else { // A user agent besides the default is selected.
629 // 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.
630 userAgentTextView.setText(userAgentDataArray[userAgentArrayPosition + 1]);
634 // Open the user agent spinner when the text view is clicked.
635 userAgentTextView.setOnClickListener((View v) -> {
636 // Open the user agent spinner.
637 userAgentSpinner.performClick();
640 // Display the font size settings.
641 if (fontSizeInt == 0) { // `0` is the code for system default font size.
642 // Set the font size to the system default
643 fontSizeSpinner.setSelection(0);
645 // Show the default font size text view.
646 defaultFontSizeTextView.setVisibility(View.VISIBLE);
648 // Hide the custom font size edit text.
649 customFontSizeEditText.setVisibility(View.GONE);
651 // 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.
652 customFontSizeEditText.setText(defaultFontSizeString);
653 } else { // A custom font size is selected.
654 // Set the spinner to the custom font size.
655 fontSizeSpinner.setSelection(1);
657 // Hide the default font size text view.
658 defaultFontSizeTextView.setVisibility(View.GONE);
660 // Show the custom font size edit text.
661 customFontSizeEditText.setVisibility(View.GONE);
663 // Set the custom font size.
664 customFontSizeEditText.setText(String.valueOf(fontSizeInt));
667 // Initialize the default font size percentage string.
668 String defaultFontSizePercentageString = defaultFontSizeString + "%";
670 // Set the default font size text in the text view.
671 defaultFontSizeTextView.setText(defaultFontSizePercentageString);
673 // Open the font size spinner when the text view is clicked.
674 defaultFontSizeTextView.setOnClickListener((View v) -> {
675 // Open the user agent spinner.
676 fontSizeSpinner.performClick();
679 // Select the swipe to refresh selection in the spinner.
680 swipeToRefreshSpinner.setSelection(swipeToRefreshInt);
682 // Set the swipe to refresh text.
683 if (defaultSwipeToRefresh) {
684 swipeToRefreshTextView.setText(swipeToRefreshArrayAdapter.getItem(DomainsDatabaseHelper.ENABLED));
686 swipeToRefreshTextView.setText(swipeToRefreshArrayAdapter.getItem(DomainsDatabaseHelper.DISABLED));
689 // Set the swipe to refresh icon and text view settings. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
690 // Doing this makes no sense until it can also be done with the preferences.
691 switch (swipeToRefreshInt) {
692 case DomainsDatabaseHelper.SYSTEM_DEFAULT:
693 if (defaultSwipeToRefresh) { // Swipe to refresh is enabled by default.
695 swipeToRefreshImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.refresh_enabled, null));
698 swipeToRefreshImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.refresh_disabled, null));
701 // Show the swipe to refresh text view.
702 swipeToRefreshTextView.setVisibility(View.VISIBLE);
705 case DomainsDatabaseHelper.ENABLED:
707 swipeToRefreshImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.refresh_enabled, null));
709 // Hide the swipe to refresh text view.
710 swipeToRefreshTextView.setVisibility(View.GONE);
713 case DomainsDatabaseHelper.DISABLED:
715 swipeToRefreshImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.refresh_disabled, null));
717 // Hide the swipe to refresh text view.
718 swipeToRefreshTextView.setVisibility(View.GONE);
722 // Open the swipe to refresh spinner when the text view is clicked.
723 swipeToRefreshTextView.setOnClickListener((View v) -> {
724 // Open the swipe to refresh spinner.
725 swipeToRefreshSpinner.performClick();
728 // Get the WebView theme string arrays.
729 String[] webViewThemeStringArray = resources.getStringArray(R.array.webview_theme_array);
730 String[] webViewThemeEntryValuesStringArray = resources.getStringArray(R.array.webview_theme_entry_values);
732 // Define an app WebView theme entry number.
733 int appWebViewThemeEntryNumber;
735 // 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.
736 if (defaultWebViewTheme.equals(webViewThemeEntryValuesStringArray[1])) { // The light theme is selected.
737 // Store the default WebView theme entry number.
738 appWebViewThemeEntryNumber = 1;
739 } else if (defaultWebViewTheme.equals(webViewThemeEntryValuesStringArray[2])) { // The dark theme is selected.
740 // Store the default WebView theme entry number.
741 appWebViewThemeEntryNumber = 2;
742 } else { // The system default theme is selected.
743 // Store the default WebView theme entry number.
744 appWebViewThemeEntryNumber = 0;
747 // Select the WebView theme in the spinner.
748 webViewThemeSpinner.setSelection(webViewThemeInt);
750 // Set the WebView theme text.
751 if (appWebViewThemeEntryNumber == DomainsDatabaseHelper.SYSTEM_DEFAULT) { // The app WebView theme is system default.
752 // Set the text according to the current UI theme.
753 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) {
754 webViewThemeTextView.setText(webViewThemeStringArray[DomainsDatabaseHelper.LIGHT_THEME]);
756 webViewThemeTextView.setText(webViewThemeStringArray[DomainsDatabaseHelper.DARK_THEME]);
758 } else { // The app WebView theme is not system default.
759 // Set the text according to the app WebView theme.
760 webViewThemeTextView.setText(webViewThemeStringArray[appWebViewThemeEntryNumber]);
763 // 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.
764 // Doing this makes no sense until it can also be done with the preferences.
765 switch (webViewThemeInt) {
766 case DomainsDatabaseHelper.SYSTEM_DEFAULT: // The domain WebView theme is system default.
767 // Set the icon according to the app WebView theme.
768 switch (appWebViewThemeEntryNumber) {
769 case DomainsDatabaseHelper.SYSTEM_DEFAULT: // The default WebView theme is system default.
770 // Set the icon according to the app theme.
771 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) {
772 // Set the light theme icon.
773 webViewThemeImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.webview_light_theme, null));
775 // Set the dark theme icon.
776 webViewThemeImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.webview_dark_theme, null));
780 case DomainsDatabaseHelper.LIGHT_THEME: // the default WebView theme is light.
782 webViewThemeImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.webview_light_theme, null));
785 case DomainsDatabaseHelper.DARK_THEME: // the default WebView theme is dark.
787 webViewThemeImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.webview_dark_theme, null));
791 // Show the WebView theme text view.
792 webViewThemeTextView.setVisibility(View.VISIBLE);
795 case DomainsDatabaseHelper.LIGHT_THEME: // The domain WebView theme is light.
797 webViewThemeImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.webview_light_theme, null));
799 // Hide the WebView theme text view.
800 webViewThemeTextView.setVisibility(View.GONE);
803 case DomainsDatabaseHelper.DARK_THEME: // The domain WebView theme is dark.
805 webViewThemeImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.webview_dark_theme, null));
807 // Hide the WebView theme text view.
808 webViewThemeTextView.setVisibility(View.GONE);
812 // Open the WebView theme spinner when the text view is clicked.
813 webViewThemeTextView.setOnClickListener((View v) -> {
814 // Open the WebView theme spinner.
815 webViewThemeSpinner.performClick();
818 // Select the wide viewport in the spinner.
819 wideViewportSpinner.setSelection(wideViewportInt);
821 // Set the default wide viewport text.
822 if (defaultWideViewport) {
823 wideViewportTextView.setText(wideViewportArrayAdapter.getItem(DomainsDatabaseHelper.ENABLED));
825 wideViewportTextView.setText(wideViewportArrayAdapter.getItem(DomainsDatabaseHelper.DISABLED));
828 // 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.
829 // Doing this makes no sense until it can also be done with the preferences.
830 switch (wideViewportInt) {
831 case DomainsDatabaseHelper.SYSTEM_DEFAULT:
833 if (defaultWideViewport) { // Wide viewport enabled by default.
834 wideViewportImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.wide_viewport_enabled, null));
835 } else { // Wide viewport disabled by default.
836 wideViewportImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.wide_viewport_disabled, null));
839 // Show the wide viewport text view.
840 wideViewportTextView.setVisibility(View.VISIBLE);
843 case DomainsDatabaseHelper.ENABLED:
844 // Set the icon according to the theme.
845 wideViewportImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.wide_viewport_enabled, null));
847 // Hide the wide viewport text view.
848 wideViewportTextView.setVisibility(View.GONE);
851 case DomainsDatabaseHelper.DISABLED:
853 wideViewportImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.wide_viewport_disabled, null));
855 // Hide the wide viewport text view.
856 wideViewportTextView.setVisibility(View.GONE);
860 // Open the wide viewport spinner when the text view is clicked.
861 wideViewportTextView.setOnClickListener((View view) -> {
862 // Open the wide viewport spinner.
863 wideViewportSpinner.performClick();
866 // Display the website images mode in the spinner.
867 displayWebpageImagesSpinner.setSelection(displayImagesInt);
869 // Set the default display images text.
870 if (defaultDisplayWebpageImages) {
871 displayImagesTextView.setText(displayImagesArrayAdapter.getItem(DomainsDatabaseHelper.ENABLED));
873 displayImagesTextView.setText(displayImagesArrayAdapter.getItem(DomainsDatabaseHelper.DISABLED));
876 // 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.
877 // Doing this makes no sense until it can also be done with the preferences.
878 switch (displayImagesInt) {
879 case DomainsDatabaseHelper.SYSTEM_DEFAULT:
880 if (defaultDisplayWebpageImages) { // Display webpage images enabled by default.
882 displayWebpageImagesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.images_enabled, null));
883 } else { // Display webpage images disabled by default.
885 displayWebpageImagesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.images_disabled, null));
888 // Show the display images text view.
889 displayImagesTextView.setVisibility(View.VISIBLE);
892 case DomainsDatabaseHelper.ENABLED:
894 displayWebpageImagesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.images_enabled, null));
896 // Hide the display images text view.
897 displayImagesTextView.setVisibility(View.GONE);
900 case DomainsDatabaseHelper.DISABLED:
902 displayWebpageImagesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.images_disabled, null));
904 // Hide the display images text view.
905 displayImagesTextView.setVisibility(View.GONE);
909 // Open the display images spinner when the text view is clicked.
910 displayImagesTextView.setOnClickListener((View view) -> {
911 // Open the user agent spinner.
912 displayWebpageImagesSpinner.performClick();
915 // Set the pinned SSL certificate icon.
916 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.
917 // Doing this makes no sense until it can also be done with the preferences.
919 pinnedSslCertificateSwitch.setChecked(true);
922 pinnedSslCertificateImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.ssl_certificate_enabled, null));
923 } else { // Pinned SSL certificate is disabled.
924 // Uncheck the switch.
925 pinnedSslCertificateSwitch.setChecked(false);
928 pinnedSslCertificateImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.ssl_certificate_disabled, null));
931 // Store the current date.
932 Date currentDate = Calendar.getInstance().getTime();
934 // Setup the string builders to display the general certificate information in blue. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
935 savedSslIssuedToONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), savedSslIssuedToONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
936 savedSslIssuedToUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), savedSslIssuedToUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
937 savedSslIssuedByCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), savedSslIssuedByCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
938 savedSslIssuedByONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), savedSslIssuedByONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
939 savedSslIssuedByUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), savedSslIssuedByUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
941 // Check the certificate Common Name against the domain name.
942 boolean savedSslCommonNameMatchesDomainName = checkDomainNameAgainstCertificate(domainNameString, savedSslIssuedToCNameString);
944 // Format the issued to Common Name color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
945 if (savedSslCommonNameMatchesDomainName) {
946 savedSslIssuedToCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), savedSslIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
948 savedSslIssuedToCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), savedSslIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
951 // Format the start date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
952 if ((savedSslStartDate != null) && savedSslStartDate.after(currentDate)) { // The certificate start date is in the future.
953 savedSslStartDateStringBuilder.setSpan(redColorSpan, startDateLabel.length(), savedSslStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
954 } else { // The certificate start date is in the past.
955 savedSslStartDateStringBuilder.setSpan(blueColorSpan, startDateLabel.length(), savedSslStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
958 // Format the end date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
959 if ((savedSslEndDate != null) && savedSslEndDate.before(currentDate)) { // The certificate end date is in the past.
960 savedSslEndDateStringBuilder.setSpan(redColorSpan, endDateLabel.length(), savedSslEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
961 } else { // The certificate end date is in the future.
962 savedSslEndDateStringBuilder.setSpan(blueColorSpan, endDateLabel.length(), savedSslEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
965 // Display the saved website SSL certificate strings.
966 savedSslIssuedToCNameTextView.setText(savedSslIssuedToCNameStringBuilder);
967 savedSslIssuedToONameTextView.setText(savedSslIssuedToONameStringBuilder);
968 savedSslIssuedToUNameTextView.setText(savedSslIssuedToUNameStringBuilder);
969 savedSslIssuedByCNameTextView.setText(savedSslIssuedByCNameStringBuilder);
970 savedSslIssuedByONameTextView.setText(savedSslIssuedByONameStringBuilder);
971 savedSslIssuedByUNameTextView.setText(savedSslIssuedByUNameStringBuilder);
972 savedSslStartDateTextView.setText(savedSslStartDateStringBuilder);
973 savedSslEndDateTextView.setText(savedSslEndDateStringBuilder);
975 // Populate the current website SSL certificate if there is one.
976 if (DomainsActivity.sslIssuedToCName != null) {
977 // Get dates from the raw long values.
978 Date currentSslStartDate = new Date(DomainsActivity.sslStartDateLong);
979 Date currentSslEndDate = new Date(DomainsActivity.sslEndDateLong);
981 // Create a spannable string builder for each text view that needs multiple colors of text.
982 SpannableStringBuilder currentSslIssuedToCNameStringBuilder = new SpannableStringBuilder(cNameLabel + DomainsActivity.sslIssuedToCName);
983 SpannableStringBuilder currentSslIssuedToONameStringBuilder = new SpannableStringBuilder(oNameLabel + DomainsActivity.sslIssuedToOName);
984 SpannableStringBuilder currentSslIssuedToUNameStringBuilder = new SpannableStringBuilder(uNameLabel + DomainsActivity.sslIssuedToUName);
985 SpannableStringBuilder currentSslIssuedByCNameStringBuilder = new SpannableStringBuilder(cNameLabel + DomainsActivity.sslIssuedByCName);
986 SpannableStringBuilder currentSslIssuedByONameStringBuilder = new SpannableStringBuilder(oNameLabel + DomainsActivity.sslIssuedByOName);
987 SpannableStringBuilder currentSslIssuedByUNameStringBuilder = new SpannableStringBuilder(uNameLabel + DomainsActivity.sslIssuedByUName);
988 SpannableStringBuilder currentSslStartDateStringBuilder = new SpannableStringBuilder(startDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG)
989 .format(currentSslStartDate));
990 SpannableStringBuilder currentSslEndDateStringBuilder = new SpannableStringBuilder(endDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG)
991 .format(currentSslEndDate));
993 // Setup the string builders to display the general certificate information in blue. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
994 currentSslIssuedToONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), currentSslIssuedToONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
995 currentSslIssuedToUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), currentSslIssuedToUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
996 currentSslIssuedByCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), currentSslIssuedByCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
997 currentSslIssuedByONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), currentSslIssuedByONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
998 currentSslIssuedByUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), currentSslIssuedByUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1000 // Check the certificate Common Name against the domain name.
1001 boolean currentSslCommonNameMatchesDomainName = checkDomainNameAgainstCertificate(domainNameString, DomainsActivity.sslIssuedToCName);
1003 // Format the issued to Common Name color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
1004 if (currentSslCommonNameMatchesDomainName) {
1005 currentSslIssuedToCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), currentSslIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1007 currentSslIssuedToCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), currentSslIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1010 // Format the start date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
1011 if (currentSslStartDate.after(currentDate)) { // The certificate start date is in the future.
1012 currentSslStartDateStringBuilder.setSpan(redColorSpan, startDateLabel.length(), currentSslStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1013 } else { // The certificate start date is in the past.
1014 currentSslStartDateStringBuilder.setSpan(blueColorSpan, startDateLabel.length(), currentSslStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1017 // Format the end date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
1018 if (currentSslEndDate.before(currentDate)) { // The certificate end date is in the past.
1019 currentSslEndDateStringBuilder.setSpan(redColorSpan, endDateLabel.length(), currentSslEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1020 } else { // The certificate end date is in the future.
1021 currentSslEndDateStringBuilder.setSpan(blueColorSpan, endDateLabel.length(), currentSslEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1024 // Display the current website SSL certificate strings.
1025 currentSslIssuedToCNameTextView.setText(currentSslIssuedToCNameStringBuilder);
1026 currentSslIssuedToONameTextView.setText(currentSslIssuedToONameStringBuilder);
1027 currentSslIssuedToUNameTextView.setText(currentSslIssuedToUNameStringBuilder);
1028 currentSslIssuedByCNameTextView.setText(currentSslIssuedByCNameStringBuilder);
1029 currentSslIssuedByONameTextView.setText(currentSslIssuedByONameStringBuilder);
1030 currentSslIssuedByUNameTextView.setText(currentSslIssuedByUNameStringBuilder);
1031 currentSslStartDateTextView.setText(currentSslStartDateStringBuilder);
1032 currentSslEndDateTextView.setText(currentSslEndDateStringBuilder);
1035 // Set the initial display status of the SSL certificates card views.
1036 if (pinnedSslCertificateSwitch.isChecked()) { // An SSL certificate is pinned.
1037 // Set the visibility of the saved SSL certificate.
1038 if (savedSslIssuedToCNameString == null) {
1039 savedSslCardView.setVisibility(View.GONE);
1041 savedSslCardView.setVisibility(View.VISIBLE);
1044 // Set the visibility of the current website SSL certificate.
1045 if (DomainsActivity.sslIssuedToCName == null) { // There is no current SSL certificate.
1046 // Hide the SSL certificate.
1047 currentSslCardView.setVisibility(View.GONE);
1049 // Show the instruction.
1050 noCurrentWebsiteCertificateTextView.setVisibility(View.VISIBLE);
1051 } else { // There is a current SSL certificate.
1052 // Show the SSL certificate.
1053 currentSslCardView.setVisibility(View.VISIBLE);
1055 // Hide the instruction.
1056 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
1059 // Set the status of the radio buttons and the card view backgrounds.
1060 if (savedSslCardView.getVisibility() == View.VISIBLE) { // The saved SSL certificate is displayed.
1061 // Check the saved SSL certificate radio button.
1062 savedSslCertificateRadioButton.setChecked(true);
1064 // Uncheck the current website SSL certificate radio button.
1065 currentWebsiteCertificateRadioButton.setChecked(false);
1067 // Darken the background of the current website SSL certificate linear layout according to the theme.
1068 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1069 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1071 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1073 } else if (currentSslCardView.getVisibility() == View.VISIBLE) { // The saved SSL certificate is hidden but the current website SSL certificate is visible.
1074 // Check the current website SSL certificate radio button.
1075 currentWebsiteCertificateRadioButton.setChecked(true);
1077 // Uncheck the saved SSL certificate radio button.
1078 savedSslCertificateRadioButton.setChecked(false);
1079 } else { // Neither SSL certificate is visible.
1080 // Uncheck both radio buttons.
1081 savedSslCertificateRadioButton.setChecked(false);
1082 currentWebsiteCertificateRadioButton.setChecked(false);
1084 } else { // An SSL certificate is not pinned.
1085 // Hide the SSl certificates and instructions.
1086 savedSslCardView.setVisibility(View.GONE);
1087 currentSslCardView.setVisibility(View.GONE);
1088 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
1090 // Uncheck the radio buttons.
1091 savedSslCertificateRadioButton.setChecked(false);
1092 currentWebsiteCertificateRadioButton.setChecked(false);
1095 // Set the pinned IP addresses icon.
1096 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.
1097 // Doing this makes no sense until it can also be done with the preferences.
1098 // Check the switch.
1099 pinnedIpAddressesSwitch.setChecked(true);
1102 pinnedIpAddressesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.ssl_certificate_enabled, null));
1103 } else { // Pinned IP Addresses is disabled.
1104 // Uncheck the switch.
1105 pinnedIpAddressesSwitch.setChecked(false);
1108 pinnedIpAddressesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.ssl_certificate_disabled, null));
1111 // Populate the saved and current IP addresses.
1112 savedIpAddressesTextView.setText(savedIpAddresses);
1113 currentIpAddressesTextView.setText(DomainsActivity.currentIpAddresses);
1115 // Set the initial display status of the IP addresses card views.
1116 if (pinnedIpAddressesSwitch.isChecked()) { // IP addresses are pinned.
1117 // Set the visibility of the saved IP addresses.
1118 if (savedIpAddresses == null) { // There are no saved IP addresses.
1119 savedIpAddressesCardView.setVisibility(View.GONE);
1120 } else { // There are saved IP addresses.
1121 savedIpAddressesCardView.setVisibility(View.VISIBLE);
1124 // Set the visibility of the current IP addresses.
1125 currentIpAddressesCardView.setVisibility(View.VISIBLE);
1127 // Set the status of the radio buttons and the card view backgrounds.
1128 if (savedIpAddressesCardView.getVisibility() == View.VISIBLE) { // The saved IP addresses are displayed.
1129 // Check the saved IP addresses radio button.
1130 savedIpAddressesRadioButton.setChecked(true);
1132 // Uncheck the current IP addresses radio button.
1133 currentIpAddressesRadioButton.setChecked(false);
1135 // Darken the background of the current IP addresses linear layout according to the theme.
1136 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1137 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1139 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1141 } else { // The saved IP addresses are hidden.
1142 // Check the current IP addresses radio button.
1143 currentIpAddressesRadioButton.setChecked(true);
1145 // Uncheck the saved IP addresses radio button.
1146 savedIpAddressesRadioButton.setChecked(false);
1148 } else { // IP addresses are not pinned.
1149 // Hide the IP addresses card views.
1150 savedIpAddressesCardView.setVisibility(View.GONE);
1151 currentIpAddressesCardView.setVisibility(View.GONE);
1153 // Uncheck the radio buttons.
1154 savedIpAddressesRadioButton.setChecked(false);
1155 currentIpAddressesRadioButton.setChecked(false);
1159 // Set the JavaScript switch listener.
1160 javaScriptSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1161 if (isChecked) { // JavaScript is enabled.
1162 // Update the JavaScript icon.
1163 javaScriptImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.javascript_enabled, null));
1165 // Enable the DOM storage `Switch`.
1166 domStorageSwitch.setEnabled(true);
1168 // Update the DOM storage icon.
1169 if (domStorageSwitch.isChecked()) { // DOM storage is enabled.
1170 domStorageImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.dom_storage_enabled, null));
1171 } else { // DOM storage is disabled.
1173 domStorageImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.dom_storage_disabled, null));
1175 } else { // JavaScript is disabled.
1176 // Update the JavaScript icon.
1177 javaScriptImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.privacy_mode, null));
1179 // Disable the DOM storage switch.
1180 domStorageSwitch.setEnabled(false);
1182 // Set the DOM storage icon.
1183 domStorageImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.dom_storage_ghosted, null));
1187 // Set the cookies switch listener.
1188 cookiesSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1189 // Update the cookies icon.
1191 cookiesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.cookies_enabled, null));
1193 cookiesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.cookies_disabled, null));
1197 // Set the DOM Storage switch listener.
1198 domStorageSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1201 domStorageImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.dom_storage_enabled, null));
1204 domStorageImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.dom_storage_disabled, null));
1208 // Set the form data switch listener. It can be removed once the minimum API >= 26.
1209 if (Build.VERSION.SDK_INT < 26) {
1210 formDataSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1213 formDataImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.form_data_enabled, null));
1216 formDataImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.form_data_disabled, null));
1221 // Set the EasyList switch listener.
1222 easyListSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1225 easyListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_ads_enabled, null));
1227 easyListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_ads_disabled, null));
1231 // Set the EasyPrivacy switch listener.
1232 easyPrivacySwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1234 if (isChecked) { // EasyPrivacy is on.
1236 easyPrivacyImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_tracking_enabled, null));
1238 easyPrivacyImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_tracking_disabled, null));
1242 // Set the Fanboy's Annoyance List switch listener.
1243 fanboysAnnoyanceListSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1244 // Update the icon and Fanboy's Social Blocking List.
1245 if (isChecked) { // Fanboy's Annoyance List is on.
1247 fanboysAnnoyanceListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.social_media_enabled, null));
1249 // Disable the Fanboy's Social Blocking List switch.
1250 fanboysSocialBlockingListSwitch.setEnabled(false);
1252 // Update the Fanboy's Social Blocking List icon.
1253 fanboysSocialBlockingListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.social_media_ghosted, null));
1254 } else { // Fanboy's Annoyance List is off.
1256 fanboysAnnoyanceListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.social_media_disabled, null));
1258 // Enable the Fanboy's Social Blocking List switch.
1259 fanboysSocialBlockingListSwitch.setEnabled(true);
1261 // Update the Fanboy's Social Blocking List icon.
1262 if (fanboysSocialBlockingListSwitch.isChecked()) {
1263 fanboysSocialBlockingListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.social_media_enabled, null));
1265 fanboysSocialBlockingListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.social_media_disabled, null));
1270 // Set the Fanboy's Social Blocking List switch listener.
1271 fanboysSocialBlockingListSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1274 fanboysSocialBlockingListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.social_media_enabled, null));
1276 fanboysSocialBlockingListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.social_media_disabled, null));
1280 // Set the UltraList switch listener.
1281 ultraListSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1284 ultraListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_ads_enabled, null));
1286 ultraListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_ads_disabled, null));
1290 // Set the UltraPrivacy switch listener.
1291 ultraPrivacySwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1294 ultraPrivacyImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_tracking_enabled, null));
1296 ultraPrivacyImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_tracking_disabled, null));
1300 // Set the block all third-party requests switch listener.
1301 blockAllThirdPartyRequestsSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1304 blockAllThirdPartyRequestsImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_all_third_party_requests_enabled, null));
1306 blockAllThirdPartyRequestsImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_all_third_party_requests_disabled, null));
1310 // Set the user agent spinner listener.
1311 userAgentSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1313 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1314 // Set the new user agent.
1316 case MainWebViewActivity.DOMAINS_SYSTEM_DEFAULT_USER_AGENT:
1317 // Show the user agent TextView.
1318 userAgentTextView.setVisibility(View.VISIBLE);
1320 // Hide the custom user agent EditText.
1321 customUserAgentEditText.setVisibility(View.GONE);
1323 // Set the user text.
1324 switch (defaultUserAgentArrayPosition) {
1325 case MainWebViewActivity.UNRECOGNIZED_USER_AGENT: // The default user agent name is not on the canonical list.
1326 // This is probably because it was set in an older version of Privacy Browser before the switch to persistent user agent names.
1327 userAgentTextView.setText(defaultUserAgentName);
1330 case MainWebViewActivity.SETTINGS_WEBVIEW_DEFAULT_USER_AGENT:
1331 // Display the `WebView` default user agent.
1332 userAgentTextView.setText(webViewDefaultUserAgentString);
1335 case MainWebViewActivity.SETTINGS_CUSTOM_USER_AGENT:
1336 // Display the custom user agent.
1337 userAgentTextView.setText(defaultCustomUserAgentString);
1341 // Get the user agent string from the user agent data array.
1342 userAgentTextView.setText(userAgentDataArray[defaultUserAgentArrayPosition]);
1346 case MainWebViewActivity.DOMAINS_WEBVIEW_DEFAULT_USER_AGENT:
1347 // Show the user agent TextView and set the text.
1348 userAgentTextView.setVisibility(View.VISIBLE);
1349 userAgentTextView.setText(webViewDefaultUserAgentString);
1351 // Hide the custom user agent EditTex.
1352 customUserAgentEditText.setVisibility(View.GONE);
1355 case MainWebViewActivity.DOMAINS_CUSTOM_USER_AGENT:
1356 // Hide the user agent TextView.
1357 userAgentTextView.setVisibility(View.GONE);
1359 // Show the custom user agent EditText and set the current user agent name as the text.
1360 customUserAgentEditText.setVisibility(View.VISIBLE);
1361 customUserAgentEditText.setText(currentUserAgentName);
1365 // 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.
1366 userAgentTextView.setVisibility(View.VISIBLE);
1367 userAgentTextView.setText(userAgentDataArray[position - 1]);
1369 // Hide `customUserAgentEditText`.
1370 customUserAgentEditText.setVisibility(View.GONE);
1375 public void onNothingSelected(AdapterView<?> parent) {
1380 // Set the font size spinner listener.
1381 fontSizeSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1383 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1384 // Update the font size display options.
1385 if (position == 0) { // The system default font size has been selected.
1386 // Show the default font size text view.
1387 defaultFontSizeTextView.setVisibility(View.VISIBLE);
1389 // Hide the custom font size edit text.
1390 customFontSizeEditText.setVisibility(View.GONE);
1391 } else { // A custom font size has been selected.
1392 // Hide the default font size text view.
1393 defaultFontSizeTextView.setVisibility(View.GONE);
1395 // Show the custom font size edit text.
1396 customFontSizeEditText.setVisibility(View.VISIBLE);
1401 public void onNothingSelected(AdapterView<?> parent) {
1406 // Set the swipe to refresh spinner listener.
1407 swipeToRefreshSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1409 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1410 // Update the icon and the visibility of the night mode text view. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
1411 // Doing this makes no sense until it can also be done with the preferences.
1413 case DomainsDatabaseHelper.SYSTEM_DEFAULT:
1414 if (defaultSwipeToRefresh) {
1416 swipeToRefreshImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.refresh_enabled, null));
1419 swipeToRefreshImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.refresh_disabled, null));
1422 // Show the swipe to refresh text view.
1423 swipeToRefreshTextView.setVisibility(View.VISIBLE);
1426 case DomainsDatabaseHelper.ENABLED:
1428 swipeToRefreshImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.refresh_enabled, null));
1430 // Hide the swipe to refresh text view.
1431 swipeToRefreshTextView.setVisibility(View.GONE);
1434 case DomainsDatabaseHelper.DISABLED:
1436 swipeToRefreshImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.refresh_disabled, null));
1438 // Hide the swipe to refresh text view.
1439 swipeToRefreshTextView.setVisibility(View.GONE);
1444 public void onNothingSelected(AdapterView<?> parent) {
1449 // Set the WebView theme spinner listener.
1450 webViewThemeSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1452 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1453 // 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.
1454 // Doing this makes no sense until it can also be done with the preferences.
1456 case DomainsDatabaseHelper.SYSTEM_DEFAULT: // the domain WebView theme is system default.
1457 // Set the icon according to the app WebView theme.
1458 switch (appWebViewThemeEntryNumber) {
1459 case DomainsDatabaseHelper.SYSTEM_DEFAULT: // The default WebView theme is system default.
1460 // Set the icon according to the app theme.
1461 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) {
1462 // Set the light theme icon.
1463 webViewThemeImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.webview_light_theme, null));
1465 // Set the dark theme icon.
1466 webViewThemeImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.webview_dark_theme, null));
1470 case DomainsDatabaseHelper.LIGHT_THEME: // The default WebView theme is light.
1472 webViewThemeImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.webview_light_theme, null));
1475 case DomainsDatabaseHelper.DARK_THEME: // The default WebView theme is dark.
1477 webViewThemeImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.webview_dark_theme, null));
1481 // Show the WebView theme text view.
1482 webViewThemeTextView.setVisibility(View.VISIBLE);
1485 case DomainsDatabaseHelper.LIGHT_THEME: // The domain WebView theme is light.
1487 webViewThemeImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.webview_light_theme, null));
1489 // Hide the WebView theme text view.
1490 webViewThemeTextView.setVisibility(View.GONE);
1493 case DomainsDatabaseHelper.DARK_THEME: // The domain WebView theme is dark.
1495 webViewThemeImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.webview_dark_theme, null));
1497 // Hide the WebView theme text view.
1498 webViewThemeTextView.setVisibility(View.GONE);
1504 public void onNothingSelected(AdapterView<?> parent) {
1509 // Set the wide viewport spinner listener.
1510 wideViewportSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1512 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1513 // Update the icon and the visibility of the wide viewport text view.
1515 case DomainsDatabaseHelper.SYSTEM_DEFAULT:
1517 if (defaultWideViewport) { // Wide viewport is enabled by default.
1518 wideViewportImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.wide_viewport_enabled, null));
1519 } else { // Wide viewport is disabled by default.
1520 wideViewportImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.wide_viewport_disabled, null));
1523 // Show the wide viewport text view.
1524 wideViewportTextView.setVisibility(View.VISIBLE);
1527 case DomainsDatabaseHelper.ENABLED:
1528 // Set the icon according to the theme.
1529 wideViewportImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.wide_viewport_enabled, null));
1531 // Hide the wide viewport text view.
1532 wideViewportTextView.setVisibility(View.GONE);
1535 case DomainsDatabaseHelper.DISABLED:
1537 wideViewportImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.wide_viewport_disabled, null));
1539 // Hid ethe wide viewport text view.
1540 wideViewportTextView.setVisibility(View.GONE);
1546 public void onNothingSelected(AdapterView<?> parent) {
1551 // Set the display webpage images spinner listener.
1552 displayWebpageImagesSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1554 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1555 // Update the icon and the visibility of the display images text view.
1557 case DomainsDatabaseHelper.SYSTEM_DEFAULT:
1558 if (defaultDisplayWebpageImages) { // Display webpage images is enabled by default.
1560 displayWebpageImagesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.images_enabled, null));
1561 } else { // Display webpage images is disabled by default.
1563 displayWebpageImagesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.images_disabled, null));
1566 // Show the display images text view.
1567 displayImagesTextView.setVisibility(View.VISIBLE);
1570 case DomainsDatabaseHelper.ENABLED:
1572 displayWebpageImagesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.images_enabled, null));
1574 // Hide the display images text view.
1575 displayImagesTextView.setVisibility(View.GONE);
1578 case DomainsDatabaseHelper.DISABLED:
1580 displayWebpageImagesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.images_disabled, null));
1582 // Hide the display images text view.
1583 displayImagesTextView.setVisibility(View.GONE);
1589 public void onNothingSelected(AdapterView<?> parent) {
1594 // Set the pinned SSL certificate switch listener.
1595 pinnedSslCertificateSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1597 if (isChecked) { // SSL certificate pinning is enabled.
1599 pinnedSslCertificateImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.ssl_certificate_enabled, null));
1601 // Update the visibility of the saved SSL certificate.
1602 if (savedSslIssuedToCNameString == null) {
1603 savedSslCardView.setVisibility(View.GONE);
1605 savedSslCardView.setVisibility(View.VISIBLE);
1608 // Update the visibility of the current website SSL certificate.
1609 if (DomainsActivity.sslIssuedToCName == null) {
1610 // Hide the SSL certificate.
1611 currentSslCardView.setVisibility(View.GONE);
1613 // Show the instruction.
1614 noCurrentWebsiteCertificateTextView.setVisibility(View.VISIBLE);
1616 // Show the SSL certificate.
1617 currentSslCardView.setVisibility(View.VISIBLE);
1619 // Hide the instruction.
1620 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
1623 // Set the status of the radio buttons.
1624 if (savedSslCardView.getVisibility() == View.VISIBLE) { // The saved SSL certificate is displayed.
1625 // Check the saved SSL certificate radio button.
1626 savedSslCertificateRadioButton.setChecked(true);
1628 // Uncheck the current website SSL certificate radio button.
1629 currentWebsiteCertificateRadioButton.setChecked(false);
1631 // Set the background of the saved SSL certificate linear layout to be transparent.
1632 savedSslCertificateLinearLayout.setBackgroundResource(R.color.transparent);
1634 // Darken the background of the current website SSL certificate linear layout according to the theme.
1635 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1636 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1638 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1641 // Scroll to the current website SSL certificate card.
1642 savedSslCardView.getParent().requestChildFocus(savedSslCardView, savedSslCardView);
1643 } else if (currentSslCardView.getVisibility() == View.VISIBLE) { // The saved SSL certificate is hidden but the current website SSL certificate is visible.
1644 // Check the current website SSL certificate radio button.
1645 currentWebsiteCertificateRadioButton.setChecked(true);
1647 // Uncheck the saved SSL certificate radio button.
1648 savedSslCertificateRadioButton.setChecked(false);
1650 // Set the background of the current website SSL certificate linear layout to be transparent.
1651 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.transparent);
1653 // Darken the background of the saved SSL certificate linear layout according to the theme.
1654 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1655 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1657 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1660 // Scroll to the current website SSL certificate card.
1661 currentSslCardView.getParent().requestChildFocus(currentSslCardView, currentSslCardView);
1662 } else { // Neither SSL certificate is visible.
1663 // Uncheck both radio buttons.
1664 savedSslCertificateRadioButton.setChecked(false);
1665 currentWebsiteCertificateRadioButton.setChecked(false);
1667 // Scroll to the current website SSL certificate card.
1668 noCurrentWebsiteCertificateTextView.getParent().requestChildFocus(noCurrentWebsiteCertificateTextView, noCurrentWebsiteCertificateTextView);
1670 } else { // SSL certificate pinning is disabled.
1672 pinnedSslCertificateImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.ssl_certificate_disabled, null));
1674 // Hide the SSl certificates and instructions.
1675 savedSslCardView.setVisibility(View.GONE);
1676 currentSslCardView.setVisibility(View.GONE);
1677 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
1679 // Uncheck the radio buttons.
1680 savedSslCertificateRadioButton.setChecked(false);
1681 currentWebsiteCertificateRadioButton.setChecked(false);
1685 savedSslCardView.setOnClickListener((View view) -> {
1686 // Check the saved SSL certificate radio button.
1687 savedSslCertificateRadioButton.setChecked(true);
1689 // Uncheck the current website SSL certificate radio button.
1690 currentWebsiteCertificateRadioButton.setChecked(false);
1692 // Set the background of the saved SSL certificate linear layout to be transparent.
1693 savedSslCertificateLinearLayout.setBackgroundResource(R.color.transparent);
1695 // Darken the background of the current website SSL certificate linear layout according to the theme.
1696 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1697 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1699 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1703 savedSslCertificateRadioButton.setOnClickListener((View view) -> {
1704 // Check the saved SSL certificate radio button.
1705 savedSslCertificateRadioButton.setChecked(true);
1707 // Uncheck the current website SSL certificate radio button.
1708 currentWebsiteCertificateRadioButton.setChecked(false);
1710 // Set the background of the saved SSL certificate linear layout to be transparent.
1711 savedSslCertificateLinearLayout.setBackgroundResource(R.color.transparent);
1713 // Darken the background of the current website SSL certificate linear layout according to the theme.
1714 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1715 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1717 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1721 currentSslCardView.setOnClickListener((View view) -> {
1722 // Check the current website SSL certificate radio button.
1723 currentWebsiteCertificateRadioButton.setChecked(true);
1725 // Uncheck the saved SSL certificate radio button.
1726 savedSslCertificateRadioButton.setChecked(false);
1728 // Set the background of the current website SSL certificate linear layout to be transparent.
1729 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.transparent);
1731 // Darken the background of the saved SSL certificate linear layout according to the theme.
1732 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1733 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1735 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1739 currentWebsiteCertificateRadioButton.setOnClickListener((View view) -> {
1740 // Check the current website SSL certificate radio button.
1741 currentWebsiteCertificateRadioButton.setChecked(true);
1743 // Uncheck the saved SSL certificate radio button.
1744 savedSslCertificateRadioButton.setChecked(false);
1746 // Set the background of the current website SSL certificate linear layout to be transparent.
1747 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.transparent);
1749 // Darken the background of the saved SSL certificate linear layout according to the theme.
1750 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1751 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1753 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1757 // Set the pinned IP addresses switch listener.
1758 pinnedIpAddressesSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1760 if (isChecked) { // IP addresses pinning is enabled.
1762 pinnedIpAddressesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.ssl_certificate_enabled, null));
1764 // Update the visibility of the saved IP addresses card view.
1765 if (savedIpAddresses == null) { // There are no saved IP addresses.
1766 savedIpAddressesCardView.setVisibility(View.GONE);
1767 } else { // There are saved IP addresses.
1768 savedIpAddressesCardView.setVisibility(View.VISIBLE);
1771 // Show the current IP addresses card view.
1772 currentIpAddressesCardView.setVisibility(View.VISIBLE);
1774 // Set the status of the radio buttons.
1775 if (savedIpAddressesCardView.getVisibility() == View.VISIBLE) { // The saved IP addresses are visible.
1776 // Check the saved IP addresses radio button.
1777 savedIpAddressesRadioButton.setChecked(true);
1779 // Uncheck the current IP addresses radio button.
1780 currentIpAddressesRadioButton.setChecked(false);
1782 // Set the background of the saved IP addresses linear layout to be transparent.
1783 savedSslCertificateLinearLayout.setBackgroundResource(R.color.transparent);
1785 // Darken the background of the current IP addresses linear layout according to the theme.
1786 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1787 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1789 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1791 } else { // The saved IP addresses are not visible.
1792 // Check the current IP addresses radio button.
1793 currentIpAddressesRadioButton.setChecked(true);
1795 // Uncheck the saved IP addresses radio button.
1796 savedIpAddressesRadioButton.setChecked(false);
1798 // Set the background of the current IP addresses linear layout to be transparent.
1799 currentIpAddressesLinearLayout.setBackgroundResource(R.color.transparent);
1801 // Darken the background of the saved IP addresses linear layout according to the theme.
1802 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1803 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1805 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1809 // Scroll to the bottom of the card views.
1810 currentIpAddressesCardView.getParent().requestChildFocus(currentIpAddressesCardView, currentIpAddressesCardView);
1811 } else { // IP addresses pinning is disabled.
1813 pinnedIpAddressesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.ssl_certificate_disabled, null));
1815 // Hide the IP addresses card views.
1816 savedIpAddressesCardView.setVisibility(View.GONE);
1817 currentIpAddressesCardView.setVisibility(View.GONE);
1819 // Uncheck the radio buttons.
1820 savedIpAddressesRadioButton.setChecked(false);
1821 currentIpAddressesRadioButton.setChecked(false);
1825 savedIpAddressesCardView.setOnClickListener((View view) -> {
1826 // Check the saved IP addresses radio button.
1827 savedIpAddressesRadioButton.setChecked(true);
1829 // Uncheck the current website IP addresses radio button.
1830 currentIpAddressesRadioButton.setChecked(false);
1832 // Set the background of the saved IP addresses linear layout to be transparent.
1833 savedIpAddressesLinearLayout.setBackgroundResource(R.color.transparent);
1835 // Darken the background of the current IP addresses linear layout according to the theme.
1836 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1837 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1839 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1843 savedIpAddressesRadioButton.setOnClickListener((View view) -> {
1844 // Check the saved IP addresses radio button.
1845 savedIpAddressesRadioButton.setChecked(true);
1847 // Uncheck the current website IP addresses radio button.
1848 currentIpAddressesRadioButton.setChecked(false);
1850 // Set the background of the saved IP addresses linear layout to be transparent.
1851 savedIpAddressesLinearLayout.setBackgroundResource(R.color.transparent);
1853 // Darken the background of the current IP addresses linear layout according to the theme.
1854 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1855 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1857 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1861 currentIpAddressesCardView.setOnClickListener((View view) -> {
1862 // Check the current IP addresses radio button.
1863 currentIpAddressesRadioButton.setChecked(true);
1865 // Uncheck the saved IP addresses radio button.
1866 savedIpAddressesRadioButton.setChecked(false);
1868 // Set the background of the current IP addresses linear layout to be transparent.
1869 currentIpAddressesLinearLayout.setBackgroundResource(R.color.transparent);
1871 // Darken the background of the saved IP addresses linear layout according to the theme.
1872 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1873 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1875 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1879 currentIpAddressesRadioButton.setOnClickListener((View view) -> {
1880 // Check the current IP addresses radio button.
1881 currentIpAddressesRadioButton.setChecked(true);
1883 // Uncheck the saved IP addresses radio button.
1884 savedIpAddressesRadioButton.setChecked(false);
1886 // Set the background of the current IP addresses linear layout to be transparent.
1887 currentIpAddressesLinearLayout.setBackgroundResource(R.color.transparent);
1889 // Darken the background of the saved IP addresses linear layout according to the theme.
1890 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1891 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1893 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1897 // Set the scroll Y.
1898 domainSettingsScrollView.post(() -> domainSettingsScrollView.setScrollY(scrollY));
1900 // Return the domain settings view.
1901 return domainSettingsView;
1904 private boolean checkDomainNameAgainstCertificate(String domainName, String certificateCommonName) {
1905 // Initialize `domainNamesMatch`.
1906 boolean domainNamesMatch = false;
1908 // Check various wildcard permutations if `domainName` and `certificateCommonName` are not empty.
1909 // `noinspection ConstantCondition` removes Android Studio's incorrect lint warning that `domainName` can never be `null`.
1910 if ((domainName != null) && (certificateCommonName != null)) {
1911 // Check if the domains match.
1912 if (domainName.equals(certificateCommonName)) {
1913 domainNamesMatch = true;
1916 // If `domainName` starts with a wildcard, check the base domain against all the subdomains of `certificateCommonName`.
1917 if (!domainNamesMatch && domainName.startsWith("*.") && (domainName.length() > 2)) {
1918 // Remove the initial `*.`.
1919 String baseDomainName = domainName.substring(2);
1921 // Setup a copy of `certificateCommonName` to test subdomains.
1922 String certificateCommonNameSubdomain = certificateCommonName;
1924 // Check all the subdomains in `certificateCommonNameSubdomain` against `baseDomainName`.
1925 while (!domainNamesMatch && certificateCommonNameSubdomain.contains(".")) { // Stop checking if we know that `domainNamesMatch` is `true` or if we run out of `.`.
1926 // Test the `certificateCommonNameSubdomain` against `baseDomainName`.
1927 if (certificateCommonNameSubdomain.equals(baseDomainName)) {
1928 domainNamesMatch = true;
1931 // Strip out the lowest subdomain of `certificateCommonNameSubdomain`.
1933 certificateCommonNameSubdomain = certificateCommonNameSubdomain.substring(certificateCommonNameSubdomain.indexOf(".") + 1);
1934 } catch (IndexOutOfBoundsException e) { // `certificateCommonNameSubdomain` ends with `.`.
1935 certificateCommonNameSubdomain = "";
1940 // If `certificateCommonName` starts with a wildcard, check the base common name against all the subdomains of `domainName`.
1941 if (!domainNamesMatch && certificateCommonName.startsWith("*.") && (certificateCommonName.length() > 2)) {
1942 // Remove the initial `*.`.
1943 String baseCertificateCommonName = certificateCommonName.substring(2);
1945 // Setup a copy of `domainName` to test subdomains.
1946 String domainNameSubdomain = domainName;
1948 // Check all the subdomains in `domainNameSubdomain` against `baseCertificateCommonName`.
1949 while (!domainNamesMatch && domainNameSubdomain.contains(".") && (domainNameSubdomain.length() > 2)) {
1950 // Test the `domainNameSubdomain` against `baseCertificateCommonName`.
1951 if (domainNameSubdomain.equals(baseCertificateCommonName)) {
1952 domainNamesMatch = true;
1955 // Strip out the lowest subdomain of `domainNameSubdomain`.
1957 domainNameSubdomain = domainNameSubdomain.substring(domainNameSubdomain.indexOf(".") + 1);
1958 } catch (IndexOutOfBoundsException e) { // `domainNameSubdomain` ends with `.`.
1959 domainNameSubdomain = "";
1964 // If both names start with a wildcard, check if the root of one contains the root of the other.
1965 if (!domainNamesMatch && domainName.startsWith("*.") && (domainName.length() > 2) && certificateCommonName.startsWith("*.") && (certificateCommonName.length() > 2)) {
1966 // Remove the wildcards.
1967 String rootDomainName = domainName.substring(2);
1968 String rootCertificateCommonName = certificateCommonName.substring(2);
1970 // Check if one name ends with the contents of the other. If so, there will be overlap in the their wildcard subdomains.
1971 if (rootDomainName.endsWith(rootCertificateCommonName) || rootCertificateCommonName.endsWith(rootDomainName)) {
1972 domainNamesMatch = true;
1977 return domainNamesMatch;