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.
205 DomainsDatabaseHelper domainsDatabaseHelper = new DomainsDatabaseHelper(requireContext());
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 || currentUserAgentName.equals(getString(R.string.custom_user_agent))) {
605 // A custom user agent is stored in the current user agent name. The second check is necessary in case the user did not change the default custom text.
606 // Set the user agent spinner to `Custom user agent`.
607 userAgentSpinner.setSelection(MainWebViewActivity.DOMAINS_CUSTOM_USER_AGENT);
609 // Hide the user agent TextView.
610 userAgentTextView.setVisibility(View.GONE);
612 // Show the custom user agent EditText and set the current user agent name as the text.
613 customUserAgentEditText.setVisibility(View.VISIBLE);
614 customUserAgentEditText.setText(currentUserAgentName);
615 } else { // The user agent name contains one of the canonical user agents.
616 // 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.
617 userAgentSpinner.setSelection(userAgentArrayPosition + 1);
619 // Show the user agent TextView.
620 userAgentTextView.setVisibility(View.VISIBLE);
622 // Hide the custom user agent EditText.
623 customUserAgentEditText.setVisibility(View.GONE);
625 // Set the user agent text.
626 if (userAgentArrayPosition == MainWebViewActivity.DOMAINS_WEBVIEW_DEFAULT_USER_AGENT) { // The WebView default user agent is selected.
627 // Display the WebView default user agent.
628 userAgentTextView.setText(webViewDefaultUserAgentString);
629 } else { // A user agent besides the default is selected.
630 // 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.
631 userAgentTextView.setText(userAgentDataArray[userAgentArrayPosition + 1]);
635 // Open the user agent spinner when the text view is clicked.
636 userAgentTextView.setOnClickListener((View v) -> {
637 // Open the user agent spinner.
638 userAgentSpinner.performClick();
641 // Display the font size settings.
642 if (fontSizeInt == 0) { // `0` is the code for system default font size.
643 // Set the font size to the system default
644 fontSizeSpinner.setSelection(0);
646 // Show the default font size text view.
647 defaultFontSizeTextView.setVisibility(View.VISIBLE);
649 // Hide the custom font size edit text.
650 customFontSizeEditText.setVisibility(View.GONE);
652 // 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.
653 customFontSizeEditText.setText(defaultFontSizeString);
654 } else { // A custom font size is selected.
655 // Set the spinner to the custom font size.
656 fontSizeSpinner.setSelection(1);
658 // Hide the default font size text view.
659 defaultFontSizeTextView.setVisibility(View.GONE);
661 // Show the custom font size edit text.
662 customFontSizeEditText.setVisibility(View.GONE);
664 // Set the custom font size.
665 customFontSizeEditText.setText(String.valueOf(fontSizeInt));
668 // Initialize the default font size percentage string.
669 String defaultFontSizePercentageString = defaultFontSizeString + "%";
671 // Set the default font size text in the text view.
672 defaultFontSizeTextView.setText(defaultFontSizePercentageString);
674 // Open the font size spinner when the text view is clicked.
675 defaultFontSizeTextView.setOnClickListener((View v) -> {
676 // Open the user agent spinner.
677 fontSizeSpinner.performClick();
680 // Select the swipe to refresh selection in the spinner.
681 swipeToRefreshSpinner.setSelection(swipeToRefreshInt);
683 // Set the swipe to refresh text.
684 if (defaultSwipeToRefresh) {
685 swipeToRefreshTextView.setText(swipeToRefreshArrayAdapter.getItem(DomainsDatabaseHelper.ENABLED));
687 swipeToRefreshTextView.setText(swipeToRefreshArrayAdapter.getItem(DomainsDatabaseHelper.DISABLED));
690 // 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.
691 // Doing this makes no sense until it can also be done with the preferences.
692 switch (swipeToRefreshInt) {
693 case DomainsDatabaseHelper.SYSTEM_DEFAULT:
694 if (defaultSwipeToRefresh) { // Swipe to refresh is enabled by default.
696 swipeToRefreshImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.refresh_enabled, null));
699 swipeToRefreshImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.refresh_disabled, null));
702 // Show the swipe to refresh text view.
703 swipeToRefreshTextView.setVisibility(View.VISIBLE);
706 case DomainsDatabaseHelper.ENABLED:
708 swipeToRefreshImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.refresh_enabled, null));
710 // Hide the swipe to refresh text view.
711 swipeToRefreshTextView.setVisibility(View.GONE);
714 case DomainsDatabaseHelper.DISABLED:
716 swipeToRefreshImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.refresh_disabled, null));
718 // Hide the swipe to refresh text view.
719 swipeToRefreshTextView.setVisibility(View.GONE);
723 // Open the swipe to refresh spinner when the text view is clicked.
724 swipeToRefreshTextView.setOnClickListener((View v) -> {
725 // Open the swipe to refresh spinner.
726 swipeToRefreshSpinner.performClick();
729 // Get the WebView theme string arrays.
730 String[] webViewThemeStringArray = resources.getStringArray(R.array.webview_theme_array);
731 String[] webViewThemeEntryValuesStringArray = resources.getStringArray(R.array.webview_theme_entry_values);
733 // Define an app WebView theme entry number.
734 int appWebViewThemeEntryNumber;
736 // 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.
737 if (defaultWebViewTheme.equals(webViewThemeEntryValuesStringArray[1])) { // The light theme is selected.
738 // Store the default WebView theme entry number.
739 appWebViewThemeEntryNumber = 1;
740 } else if (defaultWebViewTheme.equals(webViewThemeEntryValuesStringArray[2])) { // The dark theme is selected.
741 // Store the default WebView theme entry number.
742 appWebViewThemeEntryNumber = 2;
743 } else { // The system default theme is selected.
744 // Store the default WebView theme entry number.
745 appWebViewThemeEntryNumber = 0;
748 // Select the WebView theme in the spinner.
749 webViewThemeSpinner.setSelection(webViewThemeInt);
751 // Set the WebView theme text.
752 if (appWebViewThemeEntryNumber == DomainsDatabaseHelper.SYSTEM_DEFAULT) { // The app WebView theme is system default.
753 // Set the text according to the current UI theme.
754 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) {
755 webViewThemeTextView.setText(webViewThemeStringArray[DomainsDatabaseHelper.LIGHT_THEME]);
757 webViewThemeTextView.setText(webViewThemeStringArray[DomainsDatabaseHelper.DARK_THEME]);
759 } else { // The app WebView theme is not system default.
760 // Set the text according to the app WebView theme.
761 webViewThemeTextView.setText(webViewThemeStringArray[appWebViewThemeEntryNumber]);
764 // 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.
765 // Doing this makes no sense until it can also be done with the preferences.
766 switch (webViewThemeInt) {
767 case DomainsDatabaseHelper.SYSTEM_DEFAULT: // The domain WebView theme is system default.
768 // Set the icon according to the app WebView theme.
769 switch (appWebViewThemeEntryNumber) {
770 case DomainsDatabaseHelper.SYSTEM_DEFAULT: // The default WebView theme is system default.
771 // Set the icon according to the app theme.
772 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) {
773 // Set the light theme icon.
774 webViewThemeImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.webview_light_theme, null));
776 // Set the dark theme icon.
777 webViewThemeImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.webview_dark_theme, null));
781 case DomainsDatabaseHelper.LIGHT_THEME: // the default WebView theme is light.
783 webViewThemeImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.webview_light_theme, null));
786 case DomainsDatabaseHelper.DARK_THEME: // the default WebView theme is dark.
788 webViewThemeImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.webview_dark_theme, null));
792 // Show the WebView theme text view.
793 webViewThemeTextView.setVisibility(View.VISIBLE);
796 case DomainsDatabaseHelper.LIGHT_THEME: // The domain WebView theme is light.
798 webViewThemeImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.webview_light_theme, null));
800 // Hide the WebView theme text view.
801 webViewThemeTextView.setVisibility(View.GONE);
804 case DomainsDatabaseHelper.DARK_THEME: // The domain WebView theme is dark.
806 webViewThemeImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.webview_dark_theme, null));
808 // Hide the WebView theme text view.
809 webViewThemeTextView.setVisibility(View.GONE);
813 // Open the WebView theme spinner when the text view is clicked.
814 webViewThemeTextView.setOnClickListener((View v) -> {
815 // Open the WebView theme spinner.
816 webViewThemeSpinner.performClick();
819 // Select the wide viewport in the spinner.
820 wideViewportSpinner.setSelection(wideViewportInt);
822 // Set the default wide viewport text.
823 if (defaultWideViewport) {
824 wideViewportTextView.setText(wideViewportArrayAdapter.getItem(DomainsDatabaseHelper.ENABLED));
826 wideViewportTextView.setText(wideViewportArrayAdapter.getItem(DomainsDatabaseHelper.DISABLED));
829 // 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.
830 // Doing this makes no sense until it can also be done with the preferences.
831 switch (wideViewportInt) {
832 case DomainsDatabaseHelper.SYSTEM_DEFAULT:
834 if (defaultWideViewport) { // Wide viewport enabled by default.
835 wideViewportImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.wide_viewport_enabled, null));
836 } else { // Wide viewport disabled by default.
837 wideViewportImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.wide_viewport_disabled, null));
840 // Show the wide viewport text view.
841 wideViewportTextView.setVisibility(View.VISIBLE);
844 case DomainsDatabaseHelper.ENABLED:
845 // Set the icon according to the theme.
846 wideViewportImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.wide_viewport_enabled, null));
848 // Hide the wide viewport text view.
849 wideViewportTextView.setVisibility(View.GONE);
852 case DomainsDatabaseHelper.DISABLED:
854 wideViewportImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.wide_viewport_disabled, null));
856 // Hide the wide viewport text view.
857 wideViewportTextView.setVisibility(View.GONE);
861 // Open the wide viewport spinner when the text view is clicked.
862 wideViewportTextView.setOnClickListener((View view) -> {
863 // Open the wide viewport spinner.
864 wideViewportSpinner.performClick();
867 // Display the website images mode in the spinner.
868 displayWebpageImagesSpinner.setSelection(displayImagesInt);
870 // Set the default display images text.
871 if (defaultDisplayWebpageImages) {
872 displayImagesTextView.setText(displayImagesArrayAdapter.getItem(DomainsDatabaseHelper.ENABLED));
874 displayImagesTextView.setText(displayImagesArrayAdapter.getItem(DomainsDatabaseHelper.DISABLED));
877 // 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.
878 // Doing this makes no sense until it can also be done with the preferences.
879 switch (displayImagesInt) {
880 case DomainsDatabaseHelper.SYSTEM_DEFAULT:
881 if (defaultDisplayWebpageImages) { // Display webpage images enabled by default.
883 displayWebpageImagesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.images_enabled, null));
884 } else { // Display webpage images disabled by default.
886 displayWebpageImagesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.images_disabled, null));
889 // Show the display images text view.
890 displayImagesTextView.setVisibility(View.VISIBLE);
893 case DomainsDatabaseHelper.ENABLED:
895 displayWebpageImagesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.images_enabled, null));
897 // Hide the display images text view.
898 displayImagesTextView.setVisibility(View.GONE);
901 case DomainsDatabaseHelper.DISABLED:
903 displayWebpageImagesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.images_disabled, null));
905 // Hide the display images text view.
906 displayImagesTextView.setVisibility(View.GONE);
910 // Open the display images spinner when the text view is clicked.
911 displayImagesTextView.setOnClickListener((View view) -> {
912 // Open the user agent spinner.
913 displayWebpageImagesSpinner.performClick();
916 // Set the pinned SSL certificate icon.
917 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.
918 // Doing this makes no sense until it can also be done with the preferences.
920 pinnedSslCertificateSwitch.setChecked(true);
923 pinnedSslCertificateImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.ssl_certificate_enabled, null));
924 } else { // Pinned SSL certificate is disabled.
925 // Uncheck the switch.
926 pinnedSslCertificateSwitch.setChecked(false);
929 pinnedSslCertificateImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.ssl_certificate_disabled, null));
932 // Store the current date.
933 Date currentDate = Calendar.getInstance().getTime();
935 // Setup the string builders to display the general certificate information in blue. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
936 savedSslIssuedToONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), savedSslIssuedToONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
937 savedSslIssuedToUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), savedSslIssuedToUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
938 savedSslIssuedByCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), savedSslIssuedByCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
939 savedSslIssuedByONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), savedSslIssuedByONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
940 savedSslIssuedByUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), savedSslIssuedByUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
942 // Check the certificate Common Name against the domain name.
943 boolean savedSslCommonNameMatchesDomainName = checkDomainNameAgainstCertificate(domainNameString, savedSslIssuedToCNameString);
945 // Format the issued to Common Name color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
946 if (savedSslCommonNameMatchesDomainName) {
947 savedSslIssuedToCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), savedSslIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
949 savedSslIssuedToCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), savedSslIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
952 // Format the start date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
953 if ((savedSslStartDate != null) && savedSslStartDate.after(currentDate)) { // The certificate start date is in the future.
954 savedSslStartDateStringBuilder.setSpan(redColorSpan, startDateLabel.length(), savedSslStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
955 } else { // The certificate start date is in the past.
956 savedSslStartDateStringBuilder.setSpan(blueColorSpan, startDateLabel.length(), savedSslStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
959 // Format the end date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
960 if ((savedSslEndDate != null) && savedSslEndDate.before(currentDate)) { // The certificate end date is in the past.
961 savedSslEndDateStringBuilder.setSpan(redColorSpan, endDateLabel.length(), savedSslEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
962 } else { // The certificate end date is in the future.
963 savedSslEndDateStringBuilder.setSpan(blueColorSpan, endDateLabel.length(), savedSslEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
966 // Display the saved website SSL certificate strings.
967 savedSslIssuedToCNameTextView.setText(savedSslIssuedToCNameStringBuilder);
968 savedSslIssuedToONameTextView.setText(savedSslIssuedToONameStringBuilder);
969 savedSslIssuedToUNameTextView.setText(savedSslIssuedToUNameStringBuilder);
970 savedSslIssuedByCNameTextView.setText(savedSslIssuedByCNameStringBuilder);
971 savedSslIssuedByONameTextView.setText(savedSslIssuedByONameStringBuilder);
972 savedSslIssuedByUNameTextView.setText(savedSslIssuedByUNameStringBuilder);
973 savedSslStartDateTextView.setText(savedSslStartDateStringBuilder);
974 savedSslEndDateTextView.setText(savedSslEndDateStringBuilder);
976 // Populate the current website SSL certificate if there is one.
977 if (DomainsActivity.sslIssuedToCName != null) {
978 // Get dates from the raw long values.
979 Date currentSslStartDate = new Date(DomainsActivity.sslStartDateLong);
980 Date currentSslEndDate = new Date(DomainsActivity.sslEndDateLong);
982 // Create a spannable string builder for each text view that needs multiple colors of text.
983 SpannableStringBuilder currentSslIssuedToCNameStringBuilder = new SpannableStringBuilder(cNameLabel + DomainsActivity.sslIssuedToCName);
984 SpannableStringBuilder currentSslIssuedToONameStringBuilder = new SpannableStringBuilder(oNameLabel + DomainsActivity.sslIssuedToOName);
985 SpannableStringBuilder currentSslIssuedToUNameStringBuilder = new SpannableStringBuilder(uNameLabel + DomainsActivity.sslIssuedToUName);
986 SpannableStringBuilder currentSslIssuedByCNameStringBuilder = new SpannableStringBuilder(cNameLabel + DomainsActivity.sslIssuedByCName);
987 SpannableStringBuilder currentSslIssuedByONameStringBuilder = new SpannableStringBuilder(oNameLabel + DomainsActivity.sslIssuedByOName);
988 SpannableStringBuilder currentSslIssuedByUNameStringBuilder = new SpannableStringBuilder(uNameLabel + DomainsActivity.sslIssuedByUName);
989 SpannableStringBuilder currentSslStartDateStringBuilder = new SpannableStringBuilder(startDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG)
990 .format(currentSslStartDate));
991 SpannableStringBuilder currentSslEndDateStringBuilder = new SpannableStringBuilder(endDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG)
992 .format(currentSslEndDate));
994 // Setup the string builders to display the general certificate information in blue. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
995 currentSslIssuedToONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), currentSslIssuedToONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
996 currentSslIssuedToUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), currentSslIssuedToUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
997 currentSslIssuedByCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), currentSslIssuedByCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
998 currentSslIssuedByONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), currentSslIssuedByONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
999 currentSslIssuedByUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), currentSslIssuedByUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1001 // Check the certificate Common Name against the domain name.
1002 boolean currentSslCommonNameMatchesDomainName = checkDomainNameAgainstCertificate(domainNameString, DomainsActivity.sslIssuedToCName);
1004 // Format the issued to Common Name color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
1005 if (currentSslCommonNameMatchesDomainName) {
1006 currentSslIssuedToCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), currentSslIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1008 currentSslIssuedToCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), currentSslIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1011 // Format the start date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
1012 if (currentSslStartDate.after(currentDate)) { // The certificate start date is in the future.
1013 currentSslStartDateStringBuilder.setSpan(redColorSpan, startDateLabel.length(), currentSslStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1014 } else { // The certificate start date is in the past.
1015 currentSslStartDateStringBuilder.setSpan(blueColorSpan, startDateLabel.length(), currentSslStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1018 // Format the end date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
1019 if (currentSslEndDate.before(currentDate)) { // The certificate end date is in the past.
1020 currentSslEndDateStringBuilder.setSpan(redColorSpan, endDateLabel.length(), currentSslEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1021 } else { // The certificate end date is in the future.
1022 currentSslEndDateStringBuilder.setSpan(blueColorSpan, endDateLabel.length(), currentSslEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1025 // Display the current website SSL certificate strings.
1026 currentSslIssuedToCNameTextView.setText(currentSslIssuedToCNameStringBuilder);
1027 currentSslIssuedToONameTextView.setText(currentSslIssuedToONameStringBuilder);
1028 currentSslIssuedToUNameTextView.setText(currentSslIssuedToUNameStringBuilder);
1029 currentSslIssuedByCNameTextView.setText(currentSslIssuedByCNameStringBuilder);
1030 currentSslIssuedByONameTextView.setText(currentSslIssuedByONameStringBuilder);
1031 currentSslIssuedByUNameTextView.setText(currentSslIssuedByUNameStringBuilder);
1032 currentSslStartDateTextView.setText(currentSslStartDateStringBuilder);
1033 currentSslEndDateTextView.setText(currentSslEndDateStringBuilder);
1036 // Set the initial display status of the SSL certificates card views.
1037 if (pinnedSslCertificateSwitch.isChecked()) { // An SSL certificate is pinned.
1038 // Set the visibility of the saved SSL certificate.
1039 if (savedSslIssuedToCNameString == null) {
1040 savedSslCardView.setVisibility(View.GONE);
1042 savedSslCardView.setVisibility(View.VISIBLE);
1045 // Set the visibility of the current website SSL certificate.
1046 if (DomainsActivity.sslIssuedToCName == null) { // There is no current SSL certificate.
1047 // Hide the SSL certificate.
1048 currentSslCardView.setVisibility(View.GONE);
1050 // Show the instruction.
1051 noCurrentWebsiteCertificateTextView.setVisibility(View.VISIBLE);
1052 } else { // There is a current SSL certificate.
1053 // Show the SSL certificate.
1054 currentSslCardView.setVisibility(View.VISIBLE);
1056 // Hide the instruction.
1057 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
1060 // Set the status of the radio buttons and the card view backgrounds.
1061 if (savedSslCardView.getVisibility() == View.VISIBLE) { // The saved SSL certificate is displayed.
1062 // Check the saved SSL certificate radio button.
1063 savedSslCertificateRadioButton.setChecked(true);
1065 // Uncheck the current website SSL certificate radio button.
1066 currentWebsiteCertificateRadioButton.setChecked(false);
1068 // Darken the background of the current website SSL certificate linear layout according to the theme.
1069 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1070 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1072 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1074 } else if (currentSslCardView.getVisibility() == View.VISIBLE) { // The saved SSL certificate is hidden but the current website SSL certificate is visible.
1075 // Check the current website SSL certificate radio button.
1076 currentWebsiteCertificateRadioButton.setChecked(true);
1078 // Uncheck the saved SSL certificate radio button.
1079 savedSslCertificateRadioButton.setChecked(false);
1080 } else { // Neither SSL certificate is visible.
1081 // Uncheck both radio buttons.
1082 savedSslCertificateRadioButton.setChecked(false);
1083 currentWebsiteCertificateRadioButton.setChecked(false);
1085 } else { // An SSL certificate is not pinned.
1086 // Hide the SSl certificates and instructions.
1087 savedSslCardView.setVisibility(View.GONE);
1088 currentSslCardView.setVisibility(View.GONE);
1089 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
1091 // Uncheck the radio buttons.
1092 savedSslCertificateRadioButton.setChecked(false);
1093 currentWebsiteCertificateRadioButton.setChecked(false);
1096 // Set the pinned IP addresses icon.
1097 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.
1098 // Doing this makes no sense until it can also be done with the preferences.
1099 // Check the switch.
1100 pinnedIpAddressesSwitch.setChecked(true);
1103 pinnedIpAddressesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.ssl_certificate_enabled, null));
1104 } else { // Pinned IP Addresses is disabled.
1105 // Uncheck the switch.
1106 pinnedIpAddressesSwitch.setChecked(false);
1109 pinnedIpAddressesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.ssl_certificate_disabled, null));
1112 // Populate the saved and current IP addresses.
1113 savedIpAddressesTextView.setText(savedIpAddresses);
1114 currentIpAddressesTextView.setText(DomainsActivity.currentIpAddresses);
1116 // Set the initial display status of the IP addresses card views.
1117 if (pinnedIpAddressesSwitch.isChecked()) { // IP addresses are pinned.
1118 // Set the visibility of the saved IP addresses.
1119 if (savedIpAddresses == null) { // There are no saved IP addresses.
1120 savedIpAddressesCardView.setVisibility(View.GONE);
1121 } else { // There are saved IP addresses.
1122 savedIpAddressesCardView.setVisibility(View.VISIBLE);
1125 // Set the visibility of the current IP addresses.
1126 currentIpAddressesCardView.setVisibility(View.VISIBLE);
1128 // Set the status of the radio buttons and the card view backgrounds.
1129 if (savedIpAddressesCardView.getVisibility() == View.VISIBLE) { // The saved IP addresses are displayed.
1130 // Check the saved IP addresses radio button.
1131 savedIpAddressesRadioButton.setChecked(true);
1133 // Uncheck the current IP addresses radio button.
1134 currentIpAddressesRadioButton.setChecked(false);
1136 // Darken the background of the current IP addresses linear layout according to the theme.
1137 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1138 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1140 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1142 } else { // The saved IP addresses are hidden.
1143 // Check the current IP addresses radio button.
1144 currentIpAddressesRadioButton.setChecked(true);
1146 // Uncheck the saved IP addresses radio button.
1147 savedIpAddressesRadioButton.setChecked(false);
1149 } else { // IP addresses are not pinned.
1150 // Hide the IP addresses card views.
1151 savedIpAddressesCardView.setVisibility(View.GONE);
1152 currentIpAddressesCardView.setVisibility(View.GONE);
1154 // Uncheck the radio buttons.
1155 savedIpAddressesRadioButton.setChecked(false);
1156 currentIpAddressesRadioButton.setChecked(false);
1160 // Set the JavaScript switch listener.
1161 javaScriptSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1162 if (isChecked) { // JavaScript is enabled.
1163 // Update the JavaScript icon.
1164 javaScriptImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.javascript_enabled, null));
1166 // Enable the DOM storage `Switch`.
1167 domStorageSwitch.setEnabled(true);
1169 // Update the DOM storage icon.
1170 if (domStorageSwitch.isChecked()) { // DOM storage is enabled.
1171 domStorageImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.dom_storage_enabled, null));
1172 } else { // DOM storage is disabled.
1174 domStorageImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.dom_storage_disabled, null));
1176 } else { // JavaScript is disabled.
1177 // Update the JavaScript icon.
1178 javaScriptImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.privacy_mode, null));
1180 // Disable the DOM storage switch.
1181 domStorageSwitch.setEnabled(false);
1183 // Set the DOM storage icon.
1184 domStorageImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.dom_storage_ghosted, null));
1188 // Set the cookies switch listener.
1189 cookiesSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1190 // Update the cookies icon.
1192 cookiesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.cookies_enabled, null));
1194 cookiesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.cookies_disabled, null));
1198 // Set the DOM Storage switch listener.
1199 domStorageSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1202 domStorageImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.dom_storage_enabled, null));
1205 domStorageImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.dom_storage_disabled, null));
1209 // Set the form data switch listener. It can be removed once the minimum API >= 26.
1210 if (Build.VERSION.SDK_INT < 26) {
1211 formDataSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1214 formDataImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.form_data_enabled, null));
1217 formDataImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.form_data_disabled, null));
1222 // Set the EasyList switch listener.
1223 easyListSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1226 easyListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_ads_enabled, null));
1228 easyListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_ads_disabled, null));
1232 // Set the EasyPrivacy switch listener.
1233 easyPrivacySwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1235 if (isChecked) { // EasyPrivacy is on.
1237 easyPrivacyImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_tracking_enabled, null));
1239 easyPrivacyImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_tracking_disabled, null));
1243 // Set the Fanboy's Annoyance List switch listener.
1244 fanboysAnnoyanceListSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1245 // Update the icon and Fanboy's Social Blocking List.
1246 if (isChecked) { // Fanboy's Annoyance List is on.
1248 fanboysAnnoyanceListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.social_media_enabled, null));
1250 // Disable the Fanboy's Social Blocking List switch.
1251 fanboysSocialBlockingListSwitch.setEnabled(false);
1253 // Update the Fanboy's Social Blocking List icon.
1254 fanboysSocialBlockingListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.social_media_ghosted, null));
1255 } else { // Fanboy's Annoyance List is off.
1257 fanboysAnnoyanceListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.social_media_disabled, null));
1259 // Enable the Fanboy's Social Blocking List switch.
1260 fanboysSocialBlockingListSwitch.setEnabled(true);
1262 // Update the Fanboy's Social Blocking List icon.
1263 if (fanboysSocialBlockingListSwitch.isChecked()) {
1264 fanboysSocialBlockingListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.social_media_enabled, null));
1266 fanboysSocialBlockingListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.social_media_disabled, null));
1271 // Set the Fanboy's Social Blocking List switch listener.
1272 fanboysSocialBlockingListSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1275 fanboysSocialBlockingListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.social_media_enabled, null));
1277 fanboysSocialBlockingListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.social_media_disabled, null));
1281 // Set the UltraList switch listener.
1282 ultraListSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1285 ultraListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_ads_enabled, null));
1287 ultraListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_ads_disabled, null));
1291 // Set the UltraPrivacy switch listener.
1292 ultraPrivacySwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1295 ultraPrivacyImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_tracking_enabled, null));
1297 ultraPrivacyImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_tracking_disabled, null));
1301 // Set the block all third-party requests switch listener.
1302 blockAllThirdPartyRequestsSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1305 blockAllThirdPartyRequestsImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_all_third_party_requests_enabled, null));
1307 blockAllThirdPartyRequestsImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_all_third_party_requests_disabled, null));
1311 // Set the user agent spinner listener.
1312 userAgentSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1314 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1315 // Set the new user agent.
1317 case MainWebViewActivity.DOMAINS_SYSTEM_DEFAULT_USER_AGENT:
1318 // Show the user agent TextView.
1319 userAgentTextView.setVisibility(View.VISIBLE);
1321 // Hide the custom user agent EditText.
1322 customUserAgentEditText.setVisibility(View.GONE);
1324 // Set the user text.
1325 switch (defaultUserAgentArrayPosition) {
1326 case MainWebViewActivity.UNRECOGNIZED_USER_AGENT: // The default user agent name is not on the canonical list.
1327 // This is probably because it was set in an older version of Privacy Browser before the switch to persistent user agent names.
1328 userAgentTextView.setText(defaultUserAgentName);
1331 case MainWebViewActivity.SETTINGS_WEBVIEW_DEFAULT_USER_AGENT:
1332 // Display the `WebView` default user agent.
1333 userAgentTextView.setText(webViewDefaultUserAgentString);
1336 case MainWebViewActivity.SETTINGS_CUSTOM_USER_AGENT:
1337 // Display the custom user agent.
1338 userAgentTextView.setText(defaultCustomUserAgentString);
1342 // Get the user agent string from the user agent data array.
1343 userAgentTextView.setText(userAgentDataArray[defaultUserAgentArrayPosition]);
1347 case MainWebViewActivity.DOMAINS_WEBVIEW_DEFAULT_USER_AGENT:
1348 // Show the user agent TextView and set the text.
1349 userAgentTextView.setVisibility(View.VISIBLE);
1350 userAgentTextView.setText(webViewDefaultUserAgentString);
1352 // Hide the custom user agent EditTex.
1353 customUserAgentEditText.setVisibility(View.GONE);
1356 case MainWebViewActivity.DOMAINS_CUSTOM_USER_AGENT:
1357 // Hide the user agent TextView.
1358 userAgentTextView.setVisibility(View.GONE);
1360 // Show the custom user agent EditText and set the current user agent name as the text.
1361 customUserAgentEditText.setVisibility(View.VISIBLE);
1362 customUserAgentEditText.setText(currentUserAgentName);
1366 // 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.
1367 userAgentTextView.setVisibility(View.VISIBLE);
1368 userAgentTextView.setText(userAgentDataArray[position - 1]);
1370 // Hide `customUserAgentEditText`.
1371 customUserAgentEditText.setVisibility(View.GONE);
1376 public void onNothingSelected(AdapterView<?> parent) {
1381 // Set the font size spinner listener.
1382 fontSizeSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1384 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1385 // Update the font size display options.
1386 if (position == 0) { // The system default font size has been selected.
1387 // Show the default font size text view.
1388 defaultFontSizeTextView.setVisibility(View.VISIBLE);
1390 // Hide the custom font size edit text.
1391 customFontSizeEditText.setVisibility(View.GONE);
1392 } else { // A custom font size has been selected.
1393 // Hide the default font size text view.
1394 defaultFontSizeTextView.setVisibility(View.GONE);
1396 // Show the custom font size edit text.
1397 customFontSizeEditText.setVisibility(View.VISIBLE);
1402 public void onNothingSelected(AdapterView<?> parent) {
1407 // Set the swipe to refresh spinner listener.
1408 swipeToRefreshSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1410 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1411 // 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.
1412 // Doing this makes no sense until it can also be done with the preferences.
1414 case DomainsDatabaseHelper.SYSTEM_DEFAULT:
1415 if (defaultSwipeToRefresh) {
1417 swipeToRefreshImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.refresh_enabled, null));
1420 swipeToRefreshImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.refresh_disabled, null));
1423 // Show the swipe to refresh text view.
1424 swipeToRefreshTextView.setVisibility(View.VISIBLE);
1427 case DomainsDatabaseHelper.ENABLED:
1429 swipeToRefreshImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.refresh_enabled, null));
1431 // Hide the swipe to refresh text view.
1432 swipeToRefreshTextView.setVisibility(View.GONE);
1435 case DomainsDatabaseHelper.DISABLED:
1437 swipeToRefreshImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.refresh_disabled, null));
1439 // Hide the swipe to refresh text view.
1440 swipeToRefreshTextView.setVisibility(View.GONE);
1445 public void onNothingSelected(AdapterView<?> parent) {
1450 // Set the WebView theme spinner listener.
1451 webViewThemeSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1453 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1454 // 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.
1455 // Doing this makes no sense until it can also be done with the preferences.
1457 case DomainsDatabaseHelper.SYSTEM_DEFAULT: // the domain WebView theme is system default.
1458 // Set the icon according to the app WebView theme.
1459 switch (appWebViewThemeEntryNumber) {
1460 case DomainsDatabaseHelper.SYSTEM_DEFAULT: // The default WebView theme is system default.
1461 // Set the icon according to the app theme.
1462 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) {
1463 // Set the light theme icon.
1464 webViewThemeImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.webview_light_theme, null));
1466 // Set the dark theme icon.
1467 webViewThemeImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.webview_dark_theme, null));
1471 case DomainsDatabaseHelper.LIGHT_THEME: // The default WebView theme is light.
1473 webViewThemeImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.webview_light_theme, null));
1476 case DomainsDatabaseHelper.DARK_THEME: // The default WebView theme is dark.
1478 webViewThemeImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.webview_dark_theme, null));
1482 // Show the WebView theme text view.
1483 webViewThemeTextView.setVisibility(View.VISIBLE);
1486 case DomainsDatabaseHelper.LIGHT_THEME: // The domain WebView theme is light.
1488 webViewThemeImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.webview_light_theme, null));
1490 // Hide the WebView theme text view.
1491 webViewThemeTextView.setVisibility(View.GONE);
1494 case DomainsDatabaseHelper.DARK_THEME: // The domain WebView theme is dark.
1496 webViewThemeImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.webview_dark_theme, null));
1498 // Hide the WebView theme text view.
1499 webViewThemeTextView.setVisibility(View.GONE);
1505 public void onNothingSelected(AdapterView<?> parent) {
1510 // Set the wide viewport spinner listener.
1511 wideViewportSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1513 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1514 // Update the icon and the visibility of the wide viewport text view.
1516 case DomainsDatabaseHelper.SYSTEM_DEFAULT:
1518 if (defaultWideViewport) { // Wide viewport is enabled by default.
1519 wideViewportImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.wide_viewport_enabled, null));
1520 } else { // Wide viewport is disabled by default.
1521 wideViewportImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.wide_viewport_disabled, null));
1524 // Show the wide viewport text view.
1525 wideViewportTextView.setVisibility(View.VISIBLE);
1528 case DomainsDatabaseHelper.ENABLED:
1529 // Set the icon according to the theme.
1530 wideViewportImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.wide_viewport_enabled, null));
1532 // Hide the wide viewport text view.
1533 wideViewportTextView.setVisibility(View.GONE);
1536 case DomainsDatabaseHelper.DISABLED:
1538 wideViewportImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.wide_viewport_disabled, null));
1540 // Hid ethe wide viewport text view.
1541 wideViewportTextView.setVisibility(View.GONE);
1547 public void onNothingSelected(AdapterView<?> parent) {
1552 // Set the display webpage images spinner listener.
1553 displayWebpageImagesSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1555 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1556 // Update the icon and the visibility of the display images text view.
1558 case DomainsDatabaseHelper.SYSTEM_DEFAULT:
1559 if (defaultDisplayWebpageImages) { // Display webpage images is enabled by default.
1561 displayWebpageImagesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.images_enabled, null));
1562 } else { // Display webpage images is disabled by default.
1564 displayWebpageImagesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.images_disabled, null));
1567 // Show the display images text view.
1568 displayImagesTextView.setVisibility(View.VISIBLE);
1571 case DomainsDatabaseHelper.ENABLED:
1573 displayWebpageImagesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.images_enabled, null));
1575 // Hide the display images text view.
1576 displayImagesTextView.setVisibility(View.GONE);
1579 case DomainsDatabaseHelper.DISABLED:
1581 displayWebpageImagesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.images_disabled, null));
1583 // Hide the display images text view.
1584 displayImagesTextView.setVisibility(View.GONE);
1590 public void onNothingSelected(AdapterView<?> parent) {
1595 // Set the pinned SSL certificate switch listener.
1596 pinnedSslCertificateSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1598 if (isChecked) { // SSL certificate pinning is enabled.
1600 pinnedSslCertificateImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.ssl_certificate_enabled, null));
1602 // Update the visibility of the saved SSL certificate.
1603 if (savedSslIssuedToCNameString == null) {
1604 savedSslCardView.setVisibility(View.GONE);
1606 savedSslCardView.setVisibility(View.VISIBLE);
1609 // Update the visibility of the current website SSL certificate.
1610 if (DomainsActivity.sslIssuedToCName == null) {
1611 // Hide the SSL certificate.
1612 currentSslCardView.setVisibility(View.GONE);
1614 // Show the instruction.
1615 noCurrentWebsiteCertificateTextView.setVisibility(View.VISIBLE);
1617 // Show the SSL certificate.
1618 currentSslCardView.setVisibility(View.VISIBLE);
1620 // Hide the instruction.
1621 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
1624 // Set the status of the radio buttons.
1625 if (savedSslCardView.getVisibility() == View.VISIBLE) { // The saved SSL certificate is displayed.
1626 // Check the saved SSL certificate radio button.
1627 savedSslCertificateRadioButton.setChecked(true);
1629 // Uncheck the current website SSL certificate radio button.
1630 currentWebsiteCertificateRadioButton.setChecked(false);
1632 // Set the background of the saved SSL certificate linear layout to be transparent.
1633 savedSslCertificateLinearLayout.setBackgroundResource(R.color.transparent);
1635 // Darken the background of the current website SSL certificate linear layout according to the theme.
1636 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1637 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1639 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1642 // Scroll to the current website SSL certificate card.
1643 savedSslCardView.getParent().requestChildFocus(savedSslCardView, savedSslCardView);
1644 } else if (currentSslCardView.getVisibility() == View.VISIBLE) { // The saved SSL certificate is hidden but the current website SSL certificate is visible.
1645 // Check the current website SSL certificate radio button.
1646 currentWebsiteCertificateRadioButton.setChecked(true);
1648 // Uncheck the saved SSL certificate radio button.
1649 savedSslCertificateRadioButton.setChecked(false);
1651 // Set the background of the current website SSL certificate linear layout to be transparent.
1652 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.transparent);
1654 // Darken the background of the saved SSL certificate linear layout according to the theme.
1655 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1656 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1658 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1661 // Scroll to the current website SSL certificate card.
1662 currentSslCardView.getParent().requestChildFocus(currentSslCardView, currentSslCardView);
1663 } else { // Neither SSL certificate is visible.
1664 // Uncheck both radio buttons.
1665 savedSslCertificateRadioButton.setChecked(false);
1666 currentWebsiteCertificateRadioButton.setChecked(false);
1668 // Scroll to the current website SSL certificate card.
1669 noCurrentWebsiteCertificateTextView.getParent().requestChildFocus(noCurrentWebsiteCertificateTextView, noCurrentWebsiteCertificateTextView);
1671 } else { // SSL certificate pinning is disabled.
1673 pinnedSslCertificateImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.ssl_certificate_disabled, null));
1675 // Hide the SSl certificates and instructions.
1676 savedSslCardView.setVisibility(View.GONE);
1677 currentSslCardView.setVisibility(View.GONE);
1678 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
1680 // Uncheck the radio buttons.
1681 savedSslCertificateRadioButton.setChecked(false);
1682 currentWebsiteCertificateRadioButton.setChecked(false);
1686 savedSslCardView.setOnClickListener((View view) -> {
1687 // Check the saved SSL certificate radio button.
1688 savedSslCertificateRadioButton.setChecked(true);
1690 // Uncheck the current website SSL certificate radio button.
1691 currentWebsiteCertificateRadioButton.setChecked(false);
1693 // Set the background of the saved SSL certificate linear layout to be transparent.
1694 savedSslCertificateLinearLayout.setBackgroundResource(R.color.transparent);
1696 // Darken the background of the current website SSL certificate linear layout according to the theme.
1697 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1698 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1700 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1704 savedSslCertificateRadioButton.setOnClickListener((View view) -> {
1705 // Check the saved SSL certificate radio button.
1706 savedSslCertificateRadioButton.setChecked(true);
1708 // Uncheck the current website SSL certificate radio button.
1709 currentWebsiteCertificateRadioButton.setChecked(false);
1711 // Set the background of the saved SSL certificate linear layout to be transparent.
1712 savedSslCertificateLinearLayout.setBackgroundResource(R.color.transparent);
1714 // Darken the background of the current website SSL certificate linear layout according to the theme.
1715 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1716 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1718 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1722 currentSslCardView.setOnClickListener((View view) -> {
1723 // Check the current website SSL certificate radio button.
1724 currentWebsiteCertificateRadioButton.setChecked(true);
1726 // Uncheck the saved SSL certificate radio button.
1727 savedSslCertificateRadioButton.setChecked(false);
1729 // Set the background of the current website SSL certificate linear layout to be transparent.
1730 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.transparent);
1732 // Darken the background of the saved SSL certificate linear layout according to the theme.
1733 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1734 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1736 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1740 currentWebsiteCertificateRadioButton.setOnClickListener((View view) -> {
1741 // Check the current website SSL certificate radio button.
1742 currentWebsiteCertificateRadioButton.setChecked(true);
1744 // Uncheck the saved SSL certificate radio button.
1745 savedSslCertificateRadioButton.setChecked(false);
1747 // Set the background of the current website SSL certificate linear layout to be transparent.
1748 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.transparent);
1750 // Darken the background of the saved SSL certificate linear layout according to the theme.
1751 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1752 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1754 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1758 // Set the pinned IP addresses switch listener.
1759 pinnedIpAddressesSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1761 if (isChecked) { // IP addresses pinning is enabled.
1763 pinnedIpAddressesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.ssl_certificate_enabled, null));
1765 // Update the visibility of the saved IP addresses card view.
1766 if (savedIpAddresses == null) { // There are no saved IP addresses.
1767 savedIpAddressesCardView.setVisibility(View.GONE);
1768 } else { // There are saved IP addresses.
1769 savedIpAddressesCardView.setVisibility(View.VISIBLE);
1772 // Show the current IP addresses card view.
1773 currentIpAddressesCardView.setVisibility(View.VISIBLE);
1775 // Set the status of the radio buttons.
1776 if (savedIpAddressesCardView.getVisibility() == View.VISIBLE) { // The saved IP addresses are visible.
1777 // Check the saved IP addresses radio button.
1778 savedIpAddressesRadioButton.setChecked(true);
1780 // Uncheck the current IP addresses radio button.
1781 currentIpAddressesRadioButton.setChecked(false);
1783 // Set the background of the saved IP addresses linear layout to be transparent.
1784 savedSslCertificateLinearLayout.setBackgroundResource(R.color.transparent);
1786 // Darken the background of the current IP addresses linear layout according to the theme.
1787 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1788 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1790 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1792 } else { // The saved IP addresses are not visible.
1793 // Check the current IP addresses radio button.
1794 currentIpAddressesRadioButton.setChecked(true);
1796 // Uncheck the saved IP addresses radio button.
1797 savedIpAddressesRadioButton.setChecked(false);
1799 // Set the background of the current IP addresses linear layout to be transparent.
1800 currentIpAddressesLinearLayout.setBackgroundResource(R.color.transparent);
1802 // Darken the background of the saved IP addresses linear layout according to the theme.
1803 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1804 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1806 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1810 // Scroll to the bottom of the card views.
1811 currentIpAddressesCardView.getParent().requestChildFocus(currentIpAddressesCardView, currentIpAddressesCardView);
1812 } else { // IP addresses pinning is disabled.
1814 pinnedIpAddressesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.ssl_certificate_disabled, null));
1816 // Hide the IP addresses card views.
1817 savedIpAddressesCardView.setVisibility(View.GONE);
1818 currentIpAddressesCardView.setVisibility(View.GONE);
1820 // Uncheck the radio buttons.
1821 savedIpAddressesRadioButton.setChecked(false);
1822 currentIpAddressesRadioButton.setChecked(false);
1826 savedIpAddressesCardView.setOnClickListener((View view) -> {
1827 // Check the saved IP addresses radio button.
1828 savedIpAddressesRadioButton.setChecked(true);
1830 // Uncheck the current website IP addresses radio button.
1831 currentIpAddressesRadioButton.setChecked(false);
1833 // Set the background of the saved IP addresses linear layout to be transparent.
1834 savedIpAddressesLinearLayout.setBackgroundResource(R.color.transparent);
1836 // Darken the background of the current IP addresses linear layout according to the theme.
1837 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1838 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1840 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1844 savedIpAddressesRadioButton.setOnClickListener((View view) -> {
1845 // Check the saved IP addresses radio button.
1846 savedIpAddressesRadioButton.setChecked(true);
1848 // Uncheck the current website IP addresses radio button.
1849 currentIpAddressesRadioButton.setChecked(false);
1851 // Set the background of the saved IP addresses linear layout to be transparent.
1852 savedIpAddressesLinearLayout.setBackgroundResource(R.color.transparent);
1854 // Darken the background of the current IP addresses linear layout according to the theme.
1855 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1856 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1858 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1862 currentIpAddressesCardView.setOnClickListener((View view) -> {
1863 // Check the current IP addresses radio button.
1864 currentIpAddressesRadioButton.setChecked(true);
1866 // Uncheck the saved IP addresses radio button.
1867 savedIpAddressesRadioButton.setChecked(false);
1869 // Set the background of the current IP addresses linear layout to be transparent.
1870 currentIpAddressesLinearLayout.setBackgroundResource(R.color.transparent);
1872 // Darken the background of the saved IP addresses linear layout according to the theme.
1873 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1874 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1876 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1880 currentIpAddressesRadioButton.setOnClickListener((View view) -> {
1881 // Check the current IP addresses radio button.
1882 currentIpAddressesRadioButton.setChecked(true);
1884 // Uncheck the saved IP addresses radio button.
1885 savedIpAddressesRadioButton.setChecked(false);
1887 // Set the background of the current IP addresses linear layout to be transparent.
1888 currentIpAddressesLinearLayout.setBackgroundResource(R.color.transparent);
1890 // Darken the background of the saved IP addresses linear layout according to the theme.
1891 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1892 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1894 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1898 // Set the scroll Y.
1899 domainSettingsScrollView.post(() -> domainSettingsScrollView.setScrollY(scrollY));
1901 // Return the domain settings view.
1902 return domainSettingsView;
1905 private boolean checkDomainNameAgainstCertificate(String domainName, String certificateCommonName) {
1906 // Initialize `domainNamesMatch`.
1907 boolean domainNamesMatch = false;
1909 // Check various wildcard permutations if `domainName` and `certificateCommonName` are not empty.
1910 // `noinspection ConstantCondition` removes Android Studio's incorrect lint warning that `domainName` can never be `null`.
1911 if ((domainName != null) && (certificateCommonName != null)) {
1912 // Check if the domains match.
1913 if (domainName.equals(certificateCommonName)) {
1914 domainNamesMatch = true;
1917 // If `domainName` starts with a wildcard, check the base domain against all the subdomains of `certificateCommonName`.
1918 if (!domainNamesMatch && domainName.startsWith("*.") && (domainName.length() > 2)) {
1919 // Remove the initial `*.`.
1920 String baseDomainName = domainName.substring(2);
1922 // Setup a copy of `certificateCommonName` to test subdomains.
1923 String certificateCommonNameSubdomain = certificateCommonName;
1925 // Check all the subdomains in `certificateCommonNameSubdomain` against `baseDomainName`.
1926 while (!domainNamesMatch && certificateCommonNameSubdomain.contains(".")) { // Stop checking if we know that `domainNamesMatch` is `true` or if we run out of `.`.
1927 // Test the `certificateCommonNameSubdomain` against `baseDomainName`.
1928 if (certificateCommonNameSubdomain.equals(baseDomainName)) {
1929 domainNamesMatch = true;
1932 // Strip out the lowest subdomain of `certificateCommonNameSubdomain`.
1934 certificateCommonNameSubdomain = certificateCommonNameSubdomain.substring(certificateCommonNameSubdomain.indexOf(".") + 1);
1935 } catch (IndexOutOfBoundsException e) { // `certificateCommonNameSubdomain` ends with `.`.
1936 certificateCommonNameSubdomain = "";
1941 // If `certificateCommonName` starts with a wildcard, check the base common name against all the subdomains of `domainName`.
1942 if (!domainNamesMatch && certificateCommonName.startsWith("*.") && (certificateCommonName.length() > 2)) {
1943 // Remove the initial `*.`.
1944 String baseCertificateCommonName = certificateCommonName.substring(2);
1946 // Setup a copy of `domainName` to test subdomains.
1947 String domainNameSubdomain = domainName;
1949 // Check all the subdomains in `domainNameSubdomain` against `baseCertificateCommonName`.
1950 while (!domainNamesMatch && domainNameSubdomain.contains(".") && (domainNameSubdomain.length() > 2)) {
1951 // Test the `domainNameSubdomain` against `baseCertificateCommonName`.
1952 if (domainNameSubdomain.equals(baseCertificateCommonName)) {
1953 domainNamesMatch = true;
1956 // Strip out the lowest subdomain of `domainNameSubdomain`.
1958 domainNameSubdomain = domainNameSubdomain.substring(domainNameSubdomain.indexOf(".") + 1);
1959 } catch (IndexOutOfBoundsException e) { // `domainNameSubdomain` ends with `.`.
1960 domainNameSubdomain = "";
1965 // If both names start with a wildcard, check if the root of one contains the root of the other.
1966 if (!domainNamesMatch && domainName.startsWith("*.") && (domainName.length() > 2) && certificateCommonName.startsWith("*.") && (certificateCommonName.length() > 2)) {
1967 // Remove the wildcards.
1968 String rootDomainName = domainName.substring(2);
1969 String rootCertificateCommonName = certificateCommonName.substring(2);
1971 // Check if one name ends with the contents of the other. If so, there will be overlap in the their wildcard subdomains.
1972 if (rootDomainName.endsWith(rootCertificateCommonName) || rootCertificateCommonName.endsWith(rootDomainName)) {
1973 domainNamesMatch = true;
1978 return domainNamesMatch;