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.SharedPreferences;
24 import android.content.res.Configuration;
25 import android.content.res.Resources;
26 import android.database.Cursor;
27 import android.os.Build;
28 import android.os.Bundle;
29 import android.preference.PreferenceManager;
30 import android.text.Editable;
31 import android.text.SpannableStringBuilder;
32 import android.text.Spanned;
33 import android.text.TextWatcher;
34 import android.text.style.ForegroundColorSpan;
35 import android.view.LayoutInflater;
36 import android.view.View;
37 import android.view.ViewGroup;
38 import android.webkit.WebView;
39 import android.widget.AdapterView;
40 import android.widget.ArrayAdapter;
41 import android.widget.CompoundButton;
42 import android.widget.EditText;
43 import android.widget.ImageView;
44 import android.widget.LinearLayout;
45 import android.widget.RadioButton;
46 import android.widget.ScrollView;
47 import android.widget.Spinner;
48 import android.widget.TextView;
50 import androidx.annotation.NonNull;
51 import androidx.appcompat.widget.SwitchCompat;
52 import androidx.cardview.widget.CardView;
53 import androidx.core.content.res.ResourcesCompat;
54 import androidx.fragment.app.Fragment;
56 import com.stoutner.privacybrowser.R;
57 import com.stoutner.privacybrowser.activities.DomainsActivity;
58 import com.stoutner.privacybrowser.activities.MainWebViewActivity;
59 import com.stoutner.privacybrowser.helpers.DomainsDatabaseHelper;
61 import java.text.DateFormat;
62 import java.util.Calendar;
63 import java.util.Date;
65 public class DomainSettingsFragment extends Fragment {
66 // Initialize the public class constants. These are used by activities calling this fragment.
67 public static final String DATABASE_ID = "database_id";
68 public static final String SCROLL_Y = "scroll_y";
70 // Define the public variables. `databaseId` is public static so it can be accessed from `DomainsActivity`. It is also used in `onCreate()` and `onCreateView()`.
71 public static int databaseId;
73 // Define the class variables.
77 public void onCreate(Bundle savedInstanceState) {
78 // Run the default commands.
79 super.onCreate(savedInstanceState);
81 // Remove the lint warning that `getArguments` might be null.
82 assert getArguments() != null;
84 // Store the database id in `databaseId`.
85 databaseId = getArguments().getInt(DATABASE_ID);
86 scrollY = getArguments().getInt(SCROLL_Y);
89 // The deprecated `getDrawable()` must be used until the minimum API >= 21.
91 public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
92 // Inflate `domain_settings_fragment`. `false` does not attach it to the root `container`.
93 View domainSettingsView = inflater.inflate(R.layout.domain_settings_fragment, container, false);
95 // Get handles for the context and the resources.
96 Resources resources = getResources();
98 // Get the current theme status.
99 int currentThemeStatus = getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
101 // Get a handle for the shared preference.
102 SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(requireContext());
104 // Store the default settings.
105 String defaultUserAgentName = sharedPreferences.getString("user_agent", getString(R.string.user_agent_default_value));
106 String defaultCustomUserAgentString = sharedPreferences.getString("custom_user_agent", getString(R.string.custom_user_agent_default_value));
107 boolean defaultXRequestedWithHeader = sharedPreferences.getBoolean(getString(R.string.x_requested_with_header_key), true);
108 String defaultFontSizeString = sharedPreferences.getString("font_size", getString(R.string.font_size_default_value));
109 boolean defaultSwipeToRefresh = sharedPreferences.getBoolean("swipe_to_refresh", true);
110 String defaultWebViewTheme = sharedPreferences.getString("webview_theme", getString(R.string.webview_theme_default_value));
111 boolean defaultWideViewport = sharedPreferences.getBoolean("wide_viewport", true);
112 boolean defaultDisplayWebpageImages = sharedPreferences.getBoolean("display_webpage_images", true);
114 // Get handles for the views.
115 ScrollView domainSettingsScrollView = domainSettingsView.findViewById(R.id.domain_settings_scrollview);
116 EditText domainNameEditText = domainSettingsView.findViewById(R.id.domain_settings_name_edittext);
117 ImageView javaScriptImageView = domainSettingsView.findViewById(R.id.javascript_imageview);
118 SwitchCompat javaScriptSwitch = domainSettingsView.findViewById(R.id.javascript_switch);
119 ImageView cookiesImageView = domainSettingsView.findViewById(R.id.cookies_imageview);
120 SwitchCompat cookiesSwitch = domainSettingsView.findViewById(R.id.cookies_switch);
121 ImageView domStorageImageView = domainSettingsView.findViewById(R.id.dom_storage_imageview);
122 SwitchCompat domStorageSwitch = domainSettingsView.findViewById(R.id.dom_storage_switch);
123 ImageView formDataImageView = domainSettingsView.findViewById(R.id.form_data_imageview); // The form data views can be remove once the minimum API >= 26.
124 SwitchCompat formDataSwitch = domainSettingsView.findViewById(R.id.form_data_switch); // The form data views can be remove once the minimum API >= 26.
125 ImageView easyListImageView = domainSettingsView.findViewById(R.id.easylist_imageview);
126 SwitchCompat easyListSwitch = domainSettingsView.findViewById(R.id.easylist_switch);
127 ImageView easyPrivacyImageView = domainSettingsView.findViewById(R.id.easyprivacy_imageview);
128 SwitchCompat easyPrivacySwitch = domainSettingsView.findViewById(R.id.easyprivacy_switch);
129 ImageView fanboysAnnoyanceListImageView = domainSettingsView.findViewById(R.id.fanboys_annoyance_list_imageview);
130 SwitchCompat fanboysAnnoyanceListSwitch = domainSettingsView.findViewById(R.id.fanboys_annoyance_list_switch);
131 ImageView fanboysSocialBlockingListImageView = domainSettingsView.findViewById(R.id.fanboys_social_blocking_list_imageview);
132 SwitchCompat fanboysSocialBlockingListSwitch = domainSettingsView.findViewById(R.id.fanboys_social_blocking_list_switch);
133 ImageView ultraListImageView = domainSettingsView.findViewById(R.id.ultralist_imageview);
134 SwitchCompat ultraListSwitch = domainSettingsView.findViewById(R.id.ultralist_switch);
135 ImageView ultraPrivacyImageView = domainSettingsView.findViewById(R.id.ultraprivacy_imageview);
136 SwitchCompat ultraPrivacySwitch = domainSettingsView.findViewById(R.id.ultraprivacy_switch);
137 ImageView blockAllThirdPartyRequestsImageView = domainSettingsView.findViewById(R.id.block_all_third_party_requests_imageview);
138 SwitchCompat blockAllThirdPartyRequestsSwitch = domainSettingsView.findViewById(R.id.block_all_third_party_requests_switch);
139 Spinner userAgentSpinner = domainSettingsView.findViewById(R.id.user_agent_spinner);
140 TextView userAgentTextView = domainSettingsView.findViewById(R.id.user_agent_textview);
141 EditText customUserAgentEditText = domainSettingsView.findViewById(R.id.custom_user_agent_edittext);
142 ImageView xRequestedWithHeaderImageView = domainSettingsView.findViewById(R.id.x_requested_with_header_imageview);
143 Spinner xRequestedWithHeaderSpinner = domainSettingsView.findViewById(R.id.x_requested_with_header_spinner);
144 TextView xRequestedWithHeaderTextView = domainSettingsView.findViewById(R.id.x_requested_with_header_textview);
145 Spinner fontSizeSpinner = domainSettingsView.findViewById(R.id.font_size_spinner);
146 TextView defaultFontSizeTextView = domainSettingsView.findViewById(R.id.default_font_size_textview);
147 EditText customFontSizeEditText = domainSettingsView.findViewById(R.id.custom_font_size_edittext);
148 ImageView swipeToRefreshImageView = domainSettingsView.findViewById(R.id.swipe_to_refresh_imageview);
149 Spinner swipeToRefreshSpinner = domainSettingsView.findViewById(R.id.swipe_to_refresh_spinner);
150 TextView swipeToRefreshTextView = domainSettingsView.findViewById(R.id.swipe_to_refresh_textview);
151 ImageView webViewThemeImageView = domainSettingsView.findViewById(R.id.webview_theme_imageview);
152 Spinner webViewThemeSpinner = domainSettingsView.findViewById(R.id.webview_theme_spinner);
153 TextView webViewThemeTextView = domainSettingsView.findViewById(R.id.webview_theme_textview);
154 ImageView wideViewportImageView = domainSettingsView.findViewById(R.id.wide_viewport_imageview);
155 Spinner wideViewportSpinner = domainSettingsView.findViewById(R.id.wide_viewport_spinner);
156 TextView wideViewportTextView = domainSettingsView.findViewById(R.id.wide_viewport_textview);
157 ImageView displayWebpageImagesImageView = domainSettingsView.findViewById(R.id.display_webpage_images_imageview);
158 Spinner displayWebpageImagesSpinner = domainSettingsView.findViewById(R.id.display_webpage_images_spinner);
159 TextView displayImagesTextView = domainSettingsView.findViewById(R.id.display_webpage_images_textview);
160 ImageView pinnedSslCertificateImageView = domainSettingsView.findViewById(R.id.pinned_ssl_certificate_imageview);
161 SwitchCompat pinnedSslCertificateSwitch = domainSettingsView.findViewById(R.id.pinned_ssl_certificate_switch);
162 CardView savedSslCardView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_cardview);
163 LinearLayout savedSslCertificateLinearLayout = domainSettingsView.findViewById(R.id.saved_ssl_certificate_linearlayout);
164 RadioButton savedSslCertificateRadioButton = domainSettingsView.findViewById(R.id.saved_ssl_certificate_radiobutton);
165 TextView savedSslIssuedToCNameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_to_cname);
166 TextView savedSslIssuedToONameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_to_oname);
167 TextView savedSslIssuedToUNameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_to_uname);
168 TextView savedSslIssuedByCNameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_by_cname);
169 TextView savedSslIssuedByONameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_by_oname);
170 TextView savedSslIssuedByUNameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_by_uname);
171 TextView savedSslStartDateTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_start_date);
172 TextView savedSslEndDateTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_end_date);
173 CardView currentSslCardView = domainSettingsView.findViewById(R.id.current_website_certificate_cardview);
174 LinearLayout currentWebsiteCertificateLinearLayout = domainSettingsView.findViewById(R.id.current_website_certificate_linearlayout);
175 RadioButton currentWebsiteCertificateRadioButton = domainSettingsView.findViewById(R.id.current_website_certificate_radiobutton);
176 TextView currentSslIssuedToCNameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_to_cname);
177 TextView currentSslIssuedToONameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_to_oname);
178 TextView currentSslIssuedToUNameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_to_uname);
179 TextView currentSslIssuedByCNameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_by_cname);
180 TextView currentSslIssuedByONameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_by_oname);
181 TextView currentSslIssuedByUNameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_by_uname);
182 TextView currentSslStartDateTextView = domainSettingsView.findViewById(R.id.current_website_certificate_start_date);
183 TextView currentSslEndDateTextView = domainSettingsView.findViewById(R.id.current_website_certificate_end_date);
184 TextView noCurrentWebsiteCertificateTextView = domainSettingsView.findViewById(R.id.no_current_website_certificate);
185 ImageView pinnedIpAddressesImageView = domainSettingsView.findViewById(R.id.pinned_ip_addresses_imageview);
186 SwitchCompat pinnedIpAddressesSwitch = domainSettingsView.findViewById(R.id.pinned_ip_addresses_switch);
187 CardView savedIpAddressesCardView = domainSettingsView.findViewById(R.id.saved_ip_addresses_cardview);
188 LinearLayout savedIpAddressesLinearLayout = domainSettingsView.findViewById(R.id.saved_ip_addresses_linearlayout);
189 RadioButton savedIpAddressesRadioButton = domainSettingsView.findViewById(R.id.saved_ip_addresses_radiobutton);
190 TextView savedIpAddressesTextView = domainSettingsView.findViewById(R.id.saved_ip_addresses_textview);
191 CardView currentIpAddressesCardView = domainSettingsView.findViewById(R.id.current_ip_addresses_cardview);
192 LinearLayout currentIpAddressesLinearLayout = domainSettingsView.findViewById(R.id.current_ip_addresses_linearlayout);
193 RadioButton currentIpAddressesRadioButton = domainSettingsView.findViewById(R.id.current_ip_addresses_radiobutton);
194 TextView currentIpAddressesTextView = domainSettingsView.findViewById(R.id.current_ip_addresses_textview);
196 // Setup the pinned labels.
197 String cNameLabel = getString(R.string.common_name) + " ";
198 String oNameLabel = getString(R.string.organization) + " ";
199 String uNameLabel = getString(R.string.organizational_unit) + " ";
200 String startDateLabel = getString(R.string.start_date) + " ";
201 String endDateLabel = getString(R.string.end_date) + " ";
203 // Initialize the database handler.
204 DomainsDatabaseHelper domainsDatabaseHelper = new DomainsDatabaseHelper(requireContext());
206 // Get the database cursor for this ID and move it to the first row.
207 Cursor domainCursor = domainsDatabaseHelper.getCursorForId(databaseId);
208 domainCursor.moveToFirst();
210 // Save the cursor entries as variables.
211 String domainNameString = domainCursor.getString(domainCursor.getColumnIndexOrThrow(DomainsDatabaseHelper.DOMAIN_NAME));
212 int javaScriptInt = domainCursor.getInt(domainCursor.getColumnIndexOrThrow(DomainsDatabaseHelper.ENABLE_JAVASCRIPT));
213 int cookiesInt = domainCursor.getInt(domainCursor.getColumnIndexOrThrow(DomainsDatabaseHelper.COOKIES));
214 int domStorageInt = domainCursor.getInt(domainCursor.getColumnIndexOrThrow(DomainsDatabaseHelper.ENABLE_DOM_STORAGE));
215 int formDataInt = domainCursor.getInt(domainCursor.getColumnIndexOrThrow(DomainsDatabaseHelper.ENABLE_FORM_DATA)); // Form data can be remove once the minimum API >= 26.
216 int easyListInt = domainCursor.getInt(domainCursor.getColumnIndexOrThrow(DomainsDatabaseHelper.ENABLE_EASYLIST));
217 int easyPrivacyInt = domainCursor.getInt(domainCursor.getColumnIndexOrThrow(DomainsDatabaseHelper.ENABLE_EASYPRIVACY));
218 int fanboysAnnoyanceListInt = domainCursor.getInt(domainCursor.getColumnIndexOrThrow(DomainsDatabaseHelper.ENABLE_FANBOYS_ANNOYANCE_LIST));
219 int fanboysSocialBlockingListInt = domainCursor.getInt(domainCursor.getColumnIndexOrThrow(DomainsDatabaseHelper.ENABLE_FANBOYS_SOCIAL_BLOCKING_LIST));
220 int ultraListInt = domainCursor.getInt(domainCursor.getColumnIndexOrThrow(DomainsDatabaseHelper.ULTRALIST));
221 int ultraPrivacyInt = domainCursor.getInt(domainCursor.getColumnIndexOrThrow(DomainsDatabaseHelper.ENABLE_ULTRAPRIVACY));
222 int blockAllThirdPartyRequestsInt = domainCursor.getInt(domainCursor.getColumnIndexOrThrow(DomainsDatabaseHelper.BLOCK_ALL_THIRD_PARTY_REQUESTS));
223 String currentUserAgentName = domainCursor.getString(domainCursor.getColumnIndexOrThrow(DomainsDatabaseHelper.USER_AGENT));
224 int xRequestedWithHeaderInt = domainCursor.getInt(domainCursor.getColumnIndexOrThrow(DomainsDatabaseHelper.X_REQUESTED_WITH_HEADER));
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(requireContext(), R.array.translated_domain_settings_user_agent_names, R.layout.spinner_item);
255 ArrayAdapter<CharSequence> xRequestedWithHeaderArrayAdapter = ArrayAdapter.createFromResource(requireContext(), R.array.x_requested_with_header_array, R.layout.spinner_item);
256 ArrayAdapter<CharSequence> fontSizeArrayAdapter = ArrayAdapter.createFromResource(requireContext(), R.array.font_size_array, R.layout.spinner_item);
257 ArrayAdapter<CharSequence> swipeToRefreshArrayAdapter = ArrayAdapter.createFromResource(requireContext(), R.array.swipe_to_refresh_array, R.layout.spinner_item);
258 ArrayAdapter<CharSequence> webViewThemeArrayAdapter = ArrayAdapter.createFromResource(requireContext(), R.array.webview_theme_array, R.layout.spinner_item);
259 ArrayAdapter<CharSequence> wideViewportArrayAdapter = ArrayAdapter.createFromResource(requireContext(), R.array.wide_viewport_array, R.layout.spinner_item);
260 ArrayAdapter<CharSequence> displayImagesArrayAdapter = ArrayAdapter.createFromResource(requireContext(), R.array.display_webpage_images_array, R.layout.spinner_item);
262 // Set the drop down view resource on the spinners.
263 translatedUserAgentArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items);
264 xRequestedWithHeaderArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items);
265 fontSizeArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items);
266 swipeToRefreshArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items);
267 webViewThemeArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items);
268 wideViewportArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items);
269 displayImagesArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items);
271 // Set the array adapters for the spinners.
272 userAgentSpinner.setAdapter(translatedUserAgentArrayAdapter);
273 xRequestedWithHeaderSpinner.setAdapter(xRequestedWithHeaderArrayAdapter);
274 fontSizeSpinner.setAdapter(fontSizeArrayAdapter);
275 swipeToRefreshSpinner.setAdapter(swipeToRefreshArrayAdapter);
276 webViewThemeSpinner.setAdapter(webViewThemeArrayAdapter);
277 wideViewportSpinner.setAdapter(wideViewportArrayAdapter);
278 displayWebpageImagesSpinner.setAdapter(displayImagesArrayAdapter);
280 // Create a spannable string builder for each TextView that needs multiple colors of text.
281 SpannableStringBuilder savedSslIssuedToCNameStringBuilder = new SpannableStringBuilder(cNameLabel + savedSslIssuedToCNameString);
282 SpannableStringBuilder savedSslIssuedToONameStringBuilder = new SpannableStringBuilder(oNameLabel + savedSslIssuedToONameString);
283 SpannableStringBuilder savedSslIssuedToUNameStringBuilder = new SpannableStringBuilder(uNameLabel + savedSslIssuedToUNameString);
284 SpannableStringBuilder savedSslIssuedByCNameStringBuilder = new SpannableStringBuilder(cNameLabel + savedSslIssuedByCNameString);
285 SpannableStringBuilder savedSslIssuedByONameStringBuilder = new SpannableStringBuilder(oNameLabel + savedSslIssuedByONameString);
286 SpannableStringBuilder savedSslIssuedByUNameStringBuilder = new SpannableStringBuilder(uNameLabel + savedSslIssuedByUNameString);
288 // Initialize the spannable string builders for the saved SSL certificate dates.
289 SpannableStringBuilder savedSslStartDateStringBuilder;
290 SpannableStringBuilder savedSslEndDateStringBuilder;
292 // Leave the SSL certificate dates empty if they are `null`.
293 if (savedSslStartDate == null) {
294 savedSslStartDateStringBuilder = new SpannableStringBuilder(startDateLabel);
296 savedSslStartDateStringBuilder = new SpannableStringBuilder(startDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(savedSslStartDate));
299 if (savedSslEndDate == null) {
300 savedSslEndDateStringBuilder = new SpannableStringBuilder(endDateLabel);
302 savedSslEndDateStringBuilder = new SpannableStringBuilder(endDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(savedSslEndDate));
305 // Create the color spans.
306 final ForegroundColorSpan blueColorSpan = new ForegroundColorSpan(requireContext().getColor(R.color.alt_blue_text));
307 final ForegroundColorSpan redColorSpan = new ForegroundColorSpan(requireContext().getColor(R.color.red_text));
309 // Set the domain name from the the database cursor.
310 domainNameEditText.setText(domainNameString);
312 // Update the certificates' `Common Name` color when the domain name text changes.
313 domainNameEditText.addTextChangedListener(new TextWatcher() {
315 public void beforeTextChanged(CharSequence s, int start, int count, int after) {
320 public void onTextChanged(CharSequence s, int start, int before, int count) {
325 public void afterTextChanged(Editable s) {
326 // Get the new domain name.
327 String newDomainName = domainNameEditText.getText().toString();
329 // Check the saved SSL certificate against the new domain name.
330 boolean savedSslMatchesNewDomainName = checkDomainNameAgainstCertificate(newDomainName, savedSslIssuedToCNameString);
332 // Create a `SpannableStringBuilder` for the saved certificate `Common Name`.
333 SpannableStringBuilder savedSslCNameStringBuilder = new SpannableStringBuilder(cNameLabel + savedSslIssuedToCNameString);
335 // Format the saved certificate `Common Name` color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
336 if (savedSslMatchesNewDomainName) {
337 savedSslCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), savedSslCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
339 savedSslCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), savedSslCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
342 // Update the saved SSL issued to CName text view.
343 savedSslIssuedToCNameTextView.setText(savedSslCNameStringBuilder);
345 // Update the current website certificate if it exists.
346 if (DomainsActivity.sslIssuedToCName != null) {
347 // Check the current website certificate against the new domain name.
348 boolean currentSslMatchesNewDomainName = checkDomainNameAgainstCertificate(newDomainName, DomainsActivity.sslIssuedToCName);
350 // Create a `SpannableStringBuilder` for the current website certificate `Common Name`.
351 SpannableStringBuilder currentSslCNameStringBuilder = new SpannableStringBuilder(cNameLabel + DomainsActivity.sslIssuedToCName);
353 // Format the current certificate `Common Name` color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
354 if (currentSslMatchesNewDomainName) {
355 currentSslCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), currentSslCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
357 currentSslCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), currentSslCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
360 // Update the current SSL issued to CName text view.
361 currentSslIssuedToCNameTextView.setText(currentSslCNameStringBuilder);
366 // Set the switch positions.
367 javaScriptSwitch.setChecked(javaScriptInt == 1);
368 cookiesSwitch.setChecked(cookiesInt == 1);
369 domStorageSwitch.setChecked(domStorageInt == 1);
370 formDataSwitch.setChecked(formDataInt == 1); // Form data can be removed once the minimum API >= 26.
371 easyListSwitch.setChecked(easyListInt == 1);
372 easyPrivacySwitch.setChecked(easyPrivacyInt == 1);
373 fanboysAnnoyanceListSwitch.setChecked(fanboysAnnoyanceListInt == 1);
374 fanboysSocialBlockingListSwitch.setChecked(fanboysSocialBlockingListInt == 1);
375 ultraListSwitch.setChecked(ultraListInt == 1);
376 ultraPrivacySwitch.setChecked(ultraPrivacyInt == 1);
377 blockAllThirdPartyRequestsSwitch.setChecked(blockAllThirdPartyRequestsInt == 1);
378 pinnedSslCertificateSwitch.setChecked(pinnedSslCertificateInt == 1);
379 pinnedIpAddressesSwitch.setChecked(pinnedIpAddressesInt == 1);
381 // Set the switch icon colors.
382 cookiesImageView.setSelected(cookiesInt == 1);
383 domStorageImageView.setSelected(domStorageInt == 1);
384 formDataImageView.setSelected(formDataInt == 1); // Form data can be removed once the minimum API >= 26.
385 easyListImageView.setSelected(easyListInt == 1);
386 easyPrivacyImageView.setSelected(easyPrivacyInt == 1);
387 fanboysAnnoyanceListImageView.setSelected(fanboysAnnoyanceListInt == 1);
388 fanboysSocialBlockingListImageView.setSelected(fanboysSocialBlockingListInt == 1);
389 ultraListImageView.setSelected(ultraListInt == 1);
390 ultraPrivacyImageView.setSelected(ultraPrivacyInt == 1);
391 blockAllThirdPartyRequestsImageView.setSelected(blockAllThirdPartyRequestsInt == 1);
392 pinnedSslCertificateImageView.setSelected(pinnedSslCertificateInt == 1);
393 pinnedIpAddressesImageView.setSelected(pinnedIpAddressesInt == 1);
395 // Set the JavaScript icon.
396 if (javaScriptInt == 1)
397 javaScriptImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.javascript_enabled, null));
399 javaScriptImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.privacy_mode, null));
401 // Set the DOM storage switch status based on the JavaScript status.
402 domStorageSwitch.setEnabled(javaScriptInt == 1);
404 // Set the DOM storage icon ghosted status based on the JavaScript status.
405 domStorageImageView.setEnabled(javaScriptInt == 1);
407 // Set the form data visibility. Form data can be removed once the minimum API >= 26.
408 if (Build.VERSION.SDK_INT >= 26) {
409 // Hide the form data image view and switch.
410 formDataImageView.setVisibility(View.GONE);
411 formDataSwitch.setVisibility(View.GONE);
414 // Set Fanboy's Social Blocking List switch status based on the Annoyance List status.
415 fanboysSocialBlockingListSwitch.setEnabled(fanboysAnnoyanceListInt == 0);
417 // Set the Social Blocking List icon ghosted status based on the Annoyance List status.
418 fanboysSocialBlockingListImageView.setEnabled(fanboysAnnoyanceListInt == 0);
420 // Inflated a WebView to get the default user agent.
421 // `@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.
422 @SuppressLint("InflateParams") View bareWebViewLayout = inflater.inflate(R.layout.bare_webview, null, false);
423 WebView bareWebView = bareWebViewLayout.findViewById(R.id.bare_webview);
424 final String webViewDefaultUserAgentString = bareWebView.getSettings().getUserAgentString();
426 // Get a handle for the user agent array adapter. This array does not contain the `System default` entry.
427 ArrayAdapter<CharSequence> userAgentNamesArray = ArrayAdapter.createFromResource(requireContext(), R.array.user_agent_names, R.layout.spinner_item);
429 // Get the positions of the user agent and the default user agent.
430 int userAgentArrayPosition = userAgentNamesArray.getPosition(currentUserAgentName);
431 int defaultUserAgentArrayPosition = userAgentNamesArray.getPosition(defaultUserAgentName);
433 // Get a handle for the user agent data array. This array does not contain the `System default` entry.
434 String[] userAgentDataArray = resources.getStringArray(R.array.user_agent_data);
436 // Set the user agent text.
437 if (currentUserAgentName.equals(getString(R.string.system_default_user_agent))) { // Use the system default user agent.
438 // Set the user agent according to the system default.
439 switch (defaultUserAgentArrayPosition) {
440 case MainWebViewActivity.UNRECOGNIZED_USER_AGENT: // The default user agent name is not on the canonical list.
441 // This is probably because it was set in an older version of Privacy Browser before the switch to persistent user agent names.
442 userAgentTextView.setText(defaultUserAgentName);
445 case MainWebViewActivity.SETTINGS_WEBVIEW_DEFAULT_USER_AGENT:
446 // Display the `WebView` default user agent.
447 userAgentTextView.setText(webViewDefaultUserAgentString);
450 case MainWebViewActivity.SETTINGS_CUSTOM_USER_AGENT:
451 // Display the custom user agent.
452 userAgentTextView.setText(defaultCustomUserAgentString);
456 // Get the user agent string from the user agent data array.
457 userAgentTextView.setText(userAgentDataArray[defaultUserAgentArrayPosition]);
459 } else if (userAgentArrayPosition == MainWebViewActivity.UNRECOGNIZED_USER_AGENT || currentUserAgentName.equals(getString(R.string.custom_user_agent))) {
460 // 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.
461 // Set the user agent spinner to `Custom user agent`.
462 userAgentSpinner.setSelection(MainWebViewActivity.DOMAINS_CUSTOM_USER_AGENT);
464 // Hide the user agent TextView.
465 userAgentTextView.setVisibility(View.GONE);
467 // Show the custom user agent EditText and set the current user agent name as the text.
468 customUserAgentEditText.setVisibility(View.VISIBLE);
469 customUserAgentEditText.setText(currentUserAgentName);
470 } else { // The user agent name contains one of the canonical user agents.
471 // 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.
472 userAgentSpinner.setSelection(userAgentArrayPosition + 1);
474 // Show the user agent TextView.
475 userAgentTextView.setVisibility(View.VISIBLE);
477 // Hide the custom user agent EditText.
478 customUserAgentEditText.setVisibility(View.GONE);
480 // Set the user agent text.
481 if (userAgentArrayPosition == MainWebViewActivity.DOMAINS_WEBVIEW_DEFAULT_USER_AGENT) { // The WebView default user agent is selected.
482 // Display the WebView default user agent.
483 userAgentTextView.setText(webViewDefaultUserAgentString);
484 } else { // A user agent besides the default is selected.
485 // 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.
486 userAgentTextView.setText(userAgentDataArray[userAgentArrayPosition + 1]);
490 // Open the user agent spinner when the text view is clicked.
491 userAgentTextView.setOnClickListener((View v) -> {
492 // Open the user agent spinner.
493 userAgentSpinner.performClick();
496 // Select the X-Requested-With header selection in the spinner.
497 xRequestedWithHeaderSpinner.setSelection(xRequestedWithHeaderInt);
499 // Set the X-Requested-With header text.
500 if (defaultXRequestedWithHeader)
501 xRequestedWithHeaderTextView.setText(xRequestedWithHeaderArrayAdapter.getItem(DomainsDatabaseHelper.ENABLED));
503 xRequestedWithHeaderTextView.setText(xRequestedWithHeaderArrayAdapter.getItem(DomainsDatabaseHelper.DISABLED));
505 // Set the X-Requested-With header icon and text view settings.
506 switch (xRequestedWithHeaderInt) {
507 case DomainsDatabaseHelper.SYSTEM_DEFAULT:
508 // Set the icon color.
509 xRequestedWithHeaderImageView.setSelected(defaultXRequestedWithHeader);
511 // Show the X-Requested-With header text view.
512 xRequestedWithHeaderTextView.setVisibility(View.VISIBLE);
515 case DomainsDatabaseHelper.ENABLED:
516 // Set the icon color.
517 xRequestedWithHeaderImageView.setSelected(true);
519 // Hide the X-Requested-With header text view.
520 xRequestedWithHeaderTextView.setVisibility(View.GONE);
523 case DomainsDatabaseHelper.DISABLED:
524 // Set the icon color.
525 xRequestedWithHeaderImageView.setSelected(false);
527 // Hide the X-Requested-With header text view.
528 xRequestedWithHeaderTextView.setVisibility(View.GONE);
532 // Open the X-Requested-With header spinner when the text view is clicked.
533 xRequestedWithHeaderTextView.setOnClickListener((View v) -> {
534 // Open the X-Requested-With header spinner.
535 xRequestedWithHeaderSpinner.performClick();
538 // Display the font size settings.
539 if (fontSizeInt == 0) { // `0` is the code for system default font size.
540 // Set the font size to the system default
541 fontSizeSpinner.setSelection(0);
543 // Show the default font size text view.
544 defaultFontSizeTextView.setVisibility(View.VISIBLE);
546 // Hide the custom font size edit text.
547 customFontSizeEditText.setVisibility(View.GONE);
549 // 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.
550 customFontSizeEditText.setText(defaultFontSizeString);
551 } else { // A custom font size is selected.
552 // Set the spinner to the custom font size.
553 fontSizeSpinner.setSelection(1);
555 // Hide the default font size text view.
556 defaultFontSizeTextView.setVisibility(View.GONE);
558 // Show the custom font size edit text.
559 customFontSizeEditText.setVisibility(View.GONE);
561 // Set the custom font size.
562 customFontSizeEditText.setText(String.valueOf(fontSizeInt));
565 // Initialize the default font size percentage string.
566 String defaultFontSizePercentageString = defaultFontSizeString + "%";
568 // Set the default font size text in the text view.
569 defaultFontSizeTextView.setText(defaultFontSizePercentageString);
571 // Open the font size spinner when the text view is clicked.
572 defaultFontSizeTextView.setOnClickListener((View v) -> {
573 // Open the user agent spinner.
574 fontSizeSpinner.performClick();
577 // Select the swipe to refresh selection in the spinner.
578 swipeToRefreshSpinner.setSelection(swipeToRefreshInt);
580 // Set the swipe to refresh text.
581 if (defaultSwipeToRefresh)
582 swipeToRefreshTextView.setText(swipeToRefreshArrayAdapter.getItem(DomainsDatabaseHelper.ENABLED));
584 swipeToRefreshTextView.setText(swipeToRefreshArrayAdapter.getItem(DomainsDatabaseHelper.DISABLED));
586 // Set the swipe to refresh icon and text view settings.
587 switch (swipeToRefreshInt) {
588 case DomainsDatabaseHelper.SYSTEM_DEFAULT:
589 // Set the icon color.
590 swipeToRefreshImageView.setSelected(defaultSwipeToRefresh);
592 // Show the swipe to refresh text view.
593 swipeToRefreshTextView.setVisibility(View.VISIBLE);
596 case DomainsDatabaseHelper.ENABLED:
597 // Set the icon color.
598 swipeToRefreshImageView.setSelected(true);
600 // Hide the swipe to refresh text view.
601 swipeToRefreshTextView.setVisibility(View.GONE);
604 case DomainsDatabaseHelper.DISABLED:
605 // Set the icon color.
606 swipeToRefreshImageView.setSelected(false);
608 // Hide the swipe to refresh text view.
609 swipeToRefreshTextView.setVisibility(View.GONE);
613 // Open the swipe to refresh spinner when the text view is clicked.
614 swipeToRefreshTextView.setOnClickListener((View v) -> {
615 // Open the swipe to refresh spinner.
616 swipeToRefreshSpinner.performClick();
619 // Get the WebView theme string arrays.
620 String[] webViewThemeStringArray = resources.getStringArray(R.array.webview_theme_array);
621 String[] webViewThemeEntryValuesStringArray = resources.getStringArray(R.array.webview_theme_entry_values);
623 // Define an app WebView theme entry number.
624 int appWebViewThemeEntryNumber;
626 // 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.
627 if (defaultWebViewTheme.equals(webViewThemeEntryValuesStringArray[1])) { // The light theme is selected.
628 // Store the default WebView theme entry number.
629 appWebViewThemeEntryNumber = 1;
630 } else if (defaultWebViewTheme.equals(webViewThemeEntryValuesStringArray[2])) { // The dark theme is selected.
631 // Store the default WebView theme entry number.
632 appWebViewThemeEntryNumber = 2;
633 } else { // The system default theme is selected.
634 // Store the default WebView theme entry number.
635 appWebViewThemeEntryNumber = 0;
638 // Select the WebView theme in the spinner.
639 webViewThemeSpinner.setSelection(webViewThemeInt);
641 // Set the WebView theme text.
642 if (appWebViewThemeEntryNumber == DomainsDatabaseHelper.SYSTEM_DEFAULT) { // The app WebView theme is system default.
643 // Set the text according to the current UI theme.
644 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) {
645 webViewThemeTextView.setText(webViewThemeStringArray[DomainsDatabaseHelper.LIGHT_THEME]);
647 webViewThemeTextView.setText(webViewThemeStringArray[DomainsDatabaseHelper.DARK_THEME]);
649 } else { // The app WebView theme is not system default.
650 // Set the text according to the app WebView theme.
651 webViewThemeTextView.setText(webViewThemeStringArray[appWebViewThemeEntryNumber]);
654 // Set the WebView theme icon and text visibility.
655 switch (webViewThemeInt) {
656 case DomainsDatabaseHelper.SYSTEM_DEFAULT: // The domain WebView theme is system default.
657 // Set the icon according to the app WebView theme.
658 switch (appWebViewThemeEntryNumber) {
659 case DomainsDatabaseHelper.SYSTEM_DEFAULT: // The default WebView theme is system default.
660 // Set the icon color.
661 webViewThemeImageView.setSelected(currentThemeStatus == Configuration.UI_MODE_NIGHT_NO);
664 case DomainsDatabaseHelper.LIGHT_THEME: // the default WebView theme is light.
665 // Set the icon color.
666 webViewThemeImageView.setSelected(true);
669 case DomainsDatabaseHelper.DARK_THEME: // the default WebView theme is dark.
670 // Set the icon color.
671 webViewThemeImageView.setSelected(false);
675 // Show the WebView theme text view.
676 webViewThemeTextView.setVisibility(View.VISIBLE);
679 case DomainsDatabaseHelper.LIGHT_THEME: // The domain WebView theme is light.
680 // Set the icon color.
681 webViewThemeImageView.setSelected(true);
683 // Hide the WebView theme text view.
684 webViewThemeTextView.setVisibility(View.GONE);
687 case DomainsDatabaseHelper.DARK_THEME: // The domain WebView theme is dark.
688 // Set the icon color.
689 webViewThemeImageView.setSelected(false);
691 // Hide the WebView theme text view.
692 webViewThemeTextView.setVisibility(View.GONE);
696 // Open the WebView theme spinner when the text view is clicked.
697 webViewThemeTextView.setOnClickListener((View v) -> {
698 // Open the WebView theme spinner.
699 webViewThemeSpinner.performClick();
702 // Select the wide viewport in the spinner.
703 wideViewportSpinner.setSelection(wideViewportInt);
705 // Set the default wide viewport text.
706 if (defaultWideViewport)
707 wideViewportTextView.setText(wideViewportArrayAdapter.getItem(DomainsDatabaseHelper.ENABLED));
709 wideViewportTextView.setText(wideViewportArrayAdapter.getItem(DomainsDatabaseHelper.DISABLED));
711 // Set the wide viewport icon and text view settings.
712 switch (wideViewportInt) {
713 case DomainsDatabaseHelper.SYSTEM_DEFAULT:
714 // Set the icon color.
715 wideViewportImageView.setSelected(defaultWideViewport);
717 // Show the wide viewport text view.
718 wideViewportTextView.setVisibility(View.VISIBLE);
721 case DomainsDatabaseHelper.ENABLED:
722 // Set the icon color.
723 wideViewportImageView.setSelected(true);
725 // Hide the wide viewport text view.
726 wideViewportTextView.setVisibility(View.GONE);
729 case DomainsDatabaseHelper.DISABLED:
730 // Set the icon color.
731 wideViewportImageView.setSelected(false);
733 // Hide the wide viewport text view.
734 wideViewportTextView.setVisibility(View.GONE);
738 // Open the wide viewport spinner when the text view is clicked.
739 wideViewportTextView.setOnClickListener((View view) -> {
740 // Open the wide viewport spinner.
741 wideViewportSpinner.performClick();
744 // Display the website images mode in the spinner.
745 displayWebpageImagesSpinner.setSelection(displayImagesInt);
747 // Set the default display images text.
748 if (defaultDisplayWebpageImages) {
749 displayImagesTextView.setText(displayImagesArrayAdapter.getItem(DomainsDatabaseHelper.ENABLED));
751 displayImagesTextView.setText(displayImagesArrayAdapter.getItem(DomainsDatabaseHelper.DISABLED));
754 // Set the display website images icon and text view settings.
755 switch (displayImagesInt) {
756 case DomainsDatabaseHelper.SYSTEM_DEFAULT:
757 // Set the icon color.
758 displayWebpageImagesImageView.setSelected(defaultDisplayWebpageImages);
760 // Show the display images text view.
761 displayImagesTextView.setVisibility(View.VISIBLE);
764 case DomainsDatabaseHelper.ENABLED:
765 // Set the icon color.
766 displayWebpageImagesImageView.setSelected(true);
768 // Hide the display images text view.
769 displayImagesTextView.setVisibility(View.GONE);
772 case DomainsDatabaseHelper.DISABLED:
773 // Set the icon color.
774 displayWebpageImagesImageView.setSelected(false);
776 // Hide the display images text view.
777 displayImagesTextView.setVisibility(View.GONE);
781 // Open the display images spinner when the text view is clicked.
782 displayImagesTextView.setOnClickListener((View view) -> {
783 // Open the user agent spinner.
784 displayWebpageImagesSpinner.performClick();
787 // Store the current date.
788 Date currentDate = Calendar.getInstance().getTime();
790 // Setup the string builders to display the general certificate information in blue. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
791 savedSslIssuedToONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), savedSslIssuedToONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
792 savedSslIssuedToUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), savedSslIssuedToUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
793 savedSslIssuedByCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), savedSslIssuedByCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
794 savedSslIssuedByONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), savedSslIssuedByONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
795 savedSslIssuedByUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), savedSslIssuedByUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
797 // Check the certificate Common Name against the domain name.
798 boolean savedSslCommonNameMatchesDomainName = checkDomainNameAgainstCertificate(domainNameString, savedSslIssuedToCNameString);
800 // Format the issued to Common Name color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
801 if (savedSslCommonNameMatchesDomainName) {
802 savedSslIssuedToCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), savedSslIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
804 savedSslIssuedToCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), savedSslIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
807 // Format the start date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
808 if ((savedSslStartDate != null) && savedSslStartDate.after(currentDate)) { // The certificate start date is in the future.
809 savedSslStartDateStringBuilder.setSpan(redColorSpan, startDateLabel.length(), savedSslStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
810 } else { // The certificate start date is in the past.
811 savedSslStartDateStringBuilder.setSpan(blueColorSpan, startDateLabel.length(), savedSslStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
814 // Format the end date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
815 if ((savedSslEndDate != null) && savedSslEndDate.before(currentDate)) { // The certificate end date is in the past.
816 savedSslEndDateStringBuilder.setSpan(redColorSpan, endDateLabel.length(), savedSslEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
817 } else { // The certificate end date is in the future.
818 savedSslEndDateStringBuilder.setSpan(blueColorSpan, endDateLabel.length(), savedSslEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
821 // Display the saved website SSL certificate strings.
822 savedSslIssuedToCNameTextView.setText(savedSslIssuedToCNameStringBuilder);
823 savedSslIssuedToONameTextView.setText(savedSslIssuedToONameStringBuilder);
824 savedSslIssuedToUNameTextView.setText(savedSslIssuedToUNameStringBuilder);
825 savedSslIssuedByCNameTextView.setText(savedSslIssuedByCNameStringBuilder);
826 savedSslIssuedByONameTextView.setText(savedSslIssuedByONameStringBuilder);
827 savedSslIssuedByUNameTextView.setText(savedSslIssuedByUNameStringBuilder);
828 savedSslStartDateTextView.setText(savedSslStartDateStringBuilder);
829 savedSslEndDateTextView.setText(savedSslEndDateStringBuilder);
831 // Populate the current website SSL certificate if there is one.
832 if (DomainsActivity.sslIssuedToCName != null) {
833 // Get dates from the raw long values.
834 Date currentSslStartDate = new Date(DomainsActivity.sslStartDateLong);
835 Date currentSslEndDate = new Date(DomainsActivity.sslEndDateLong);
837 // Create a spannable string builder for each text view that needs multiple colors of text.
838 SpannableStringBuilder currentSslIssuedToCNameStringBuilder = new SpannableStringBuilder(cNameLabel + DomainsActivity.sslIssuedToCName);
839 SpannableStringBuilder currentSslIssuedToONameStringBuilder = new SpannableStringBuilder(oNameLabel + DomainsActivity.sslIssuedToOName);
840 SpannableStringBuilder currentSslIssuedToUNameStringBuilder = new SpannableStringBuilder(uNameLabel + DomainsActivity.sslIssuedToUName);
841 SpannableStringBuilder currentSslIssuedByCNameStringBuilder = new SpannableStringBuilder(cNameLabel + DomainsActivity.sslIssuedByCName);
842 SpannableStringBuilder currentSslIssuedByONameStringBuilder = new SpannableStringBuilder(oNameLabel + DomainsActivity.sslIssuedByOName);
843 SpannableStringBuilder currentSslIssuedByUNameStringBuilder = new SpannableStringBuilder(uNameLabel + DomainsActivity.sslIssuedByUName);
844 SpannableStringBuilder currentSslStartDateStringBuilder = new SpannableStringBuilder(startDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG)
845 .format(currentSslStartDate));
846 SpannableStringBuilder currentSslEndDateStringBuilder = new SpannableStringBuilder(endDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG)
847 .format(currentSslEndDate));
849 // Setup the string builders to display the general certificate information in blue. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
850 currentSslIssuedToONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), currentSslIssuedToONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
851 currentSslIssuedToUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), currentSslIssuedToUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
852 currentSslIssuedByCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), currentSslIssuedByCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
853 currentSslIssuedByONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), currentSslIssuedByONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
854 currentSslIssuedByUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), currentSslIssuedByUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
856 // Check the certificate Common Name against the domain name.
857 boolean currentSslCommonNameMatchesDomainName = checkDomainNameAgainstCertificate(domainNameString, DomainsActivity.sslIssuedToCName);
859 // Format the issued to Common Name color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
860 if (currentSslCommonNameMatchesDomainName) {
861 currentSslIssuedToCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), currentSslIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
863 currentSslIssuedToCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), currentSslIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
866 // Format the start date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
867 if (currentSslStartDate.after(currentDate)) { // The certificate start date is in the future.
868 currentSslStartDateStringBuilder.setSpan(redColorSpan, startDateLabel.length(), currentSslStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
869 } else { // The certificate start date is in the past.
870 currentSslStartDateStringBuilder.setSpan(blueColorSpan, startDateLabel.length(), currentSslStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
873 // Format the end date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
874 if (currentSslEndDate.before(currentDate)) { // The certificate end date is in the past.
875 currentSslEndDateStringBuilder.setSpan(redColorSpan, endDateLabel.length(), currentSslEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
876 } else { // The certificate end date is in the future.
877 currentSslEndDateStringBuilder.setSpan(blueColorSpan, endDateLabel.length(), currentSslEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
880 // Display the current website SSL certificate strings.
881 currentSslIssuedToCNameTextView.setText(currentSslIssuedToCNameStringBuilder);
882 currentSslIssuedToONameTextView.setText(currentSslIssuedToONameStringBuilder);
883 currentSslIssuedToUNameTextView.setText(currentSslIssuedToUNameStringBuilder);
884 currentSslIssuedByCNameTextView.setText(currentSslIssuedByCNameStringBuilder);
885 currentSslIssuedByONameTextView.setText(currentSslIssuedByONameStringBuilder);
886 currentSslIssuedByUNameTextView.setText(currentSslIssuedByUNameStringBuilder);
887 currentSslStartDateTextView.setText(currentSslStartDateStringBuilder);
888 currentSslEndDateTextView.setText(currentSslEndDateStringBuilder);
891 // Set the initial display status of the SSL certificates card views.
892 if (pinnedSslCertificateSwitch.isChecked()) { // An SSL certificate is pinned.
893 // Set the visibility of the saved SSL certificate.
894 if (savedSslIssuedToCNameString == null) {
895 savedSslCardView.setVisibility(View.GONE);
897 savedSslCardView.setVisibility(View.VISIBLE);
900 // Set the visibility of the current website SSL certificate.
901 if (DomainsActivity.sslIssuedToCName == null) { // There is no current SSL certificate.
902 // Hide the SSL certificate.
903 currentSslCardView.setVisibility(View.GONE);
905 // Show the instruction.
906 noCurrentWebsiteCertificateTextView.setVisibility(View.VISIBLE);
907 } else { // There is a current SSL certificate.
908 // Show the SSL certificate.
909 currentSslCardView.setVisibility(View.VISIBLE);
911 // Hide the instruction.
912 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
915 // Set the status of the radio buttons and the card view backgrounds.
916 if (savedSslCardView.getVisibility() == View.VISIBLE) { // The saved SSL certificate is displayed.
917 // Check the saved SSL certificate radio button.
918 savedSslCertificateRadioButton.setChecked(true);
920 // Uncheck the current website SSL certificate radio button.
921 currentWebsiteCertificateRadioButton.setChecked(false);
923 // Darken the background of the current website SSL certificate linear layout according to the theme.
924 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
925 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
927 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
929 } else if (currentSslCardView.getVisibility() == View.VISIBLE) { // The saved SSL certificate is hidden but the current website SSL certificate is visible.
930 // Check the current website SSL certificate radio button.
931 currentWebsiteCertificateRadioButton.setChecked(true);
933 // Uncheck the saved SSL certificate radio button.
934 savedSslCertificateRadioButton.setChecked(false);
935 } else { // Neither SSL certificate is visible.
936 // Uncheck both radio buttons.
937 savedSslCertificateRadioButton.setChecked(false);
938 currentWebsiteCertificateRadioButton.setChecked(false);
940 } else { // An SSL certificate is not pinned.
941 // Hide the SSl certificates and instructions.
942 savedSslCardView.setVisibility(View.GONE);
943 currentSslCardView.setVisibility(View.GONE);
944 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
946 // Uncheck the radio buttons.
947 savedSslCertificateRadioButton.setChecked(false);
948 currentWebsiteCertificateRadioButton.setChecked(false);
951 // Populate the saved and current IP addresses.
952 savedIpAddressesTextView.setText(savedIpAddresses);
953 currentIpAddressesTextView.setText(DomainsActivity.currentIpAddresses);
955 // Set the initial display status of the IP addresses card views.
956 if (pinnedIpAddressesSwitch.isChecked()) { // IP addresses are pinned.
957 // Set the visibility of the saved IP addresses.
958 if (savedIpAddresses == null) { // There are no saved IP addresses.
959 savedIpAddressesCardView.setVisibility(View.GONE);
960 } else { // There are saved IP addresses.
961 savedIpAddressesCardView.setVisibility(View.VISIBLE);
964 // Set the visibility of the current IP addresses.
965 currentIpAddressesCardView.setVisibility(View.VISIBLE);
967 // Set the status of the radio buttons and the card view backgrounds.
968 if (savedIpAddressesCardView.getVisibility() == View.VISIBLE) { // The saved IP addresses are displayed.
969 // Check the saved IP addresses radio button.
970 savedIpAddressesRadioButton.setChecked(true);
972 // Uncheck the current IP addresses radio button.
973 currentIpAddressesRadioButton.setChecked(false);
975 // Darken the background of the current IP addresses linear layout according to the theme.
976 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
977 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
979 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
981 } else { // The saved IP addresses are hidden.
982 // Check the current IP addresses radio button.
983 currentIpAddressesRadioButton.setChecked(true);
985 // Uncheck the saved IP addresses radio button.
986 savedIpAddressesRadioButton.setChecked(false);
988 } else { // IP addresses are not pinned.
989 // Hide the IP addresses card views.
990 savedIpAddressesCardView.setVisibility(View.GONE);
991 currentIpAddressesCardView.setVisibility(View.GONE);
993 // Uncheck the radio buttons.
994 savedIpAddressesRadioButton.setChecked(false);
995 currentIpAddressesRadioButton.setChecked(false);
999 // Set the JavaScript switch listener.
1000 javaScriptSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1001 // Update the JavaScript icon.
1003 javaScriptImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.javascript_enabled, null));
1005 javaScriptImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.privacy_mode, null));
1007 // Set the DOM storage switch status.
1008 domStorageSwitch.setEnabled(isChecked);
1010 // Set the DOM storage ghosted icon status.
1011 domStorageImageView.setEnabled(isChecked);
1014 // Set the cookies switch listener.
1015 cookiesSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1016 // Update the icon color.
1017 cookiesImageView.setSelected(isChecked);
1020 // Set the DOM Storage switch listener.
1021 domStorageSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1022 // Update the icon color.
1023 domStorageImageView.setSelected(isChecked);
1026 // Set the form data switch listener. It can be removed once the minimum API >= 26.
1027 if (Build.VERSION.SDK_INT < 26) {
1028 formDataSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1029 // Update the icon color.
1030 formDataImageView.setSelected(isChecked);
1034 // Set the EasyList switch listener.
1035 easyListSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1036 // Update the icon color.
1037 easyListImageView.setSelected(isChecked);
1040 // Set the EasyPrivacy switch listener.
1041 easyPrivacySwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1042 // Update the icon color.
1043 easyPrivacyImageView.setSelected(isChecked);
1046 // Set the Fanboy's Annoyance List switch listener.
1047 fanboysAnnoyanceListSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1048 // Update the icon color.
1049 fanboysAnnoyanceListImageView.setSelected(isChecked);
1052 // Set Fanboy's Social Blocking List switch position.
1053 fanboysSocialBlockingListSwitch.setEnabled(!isChecked);
1055 // Set the Social Blocking List icon ghosted status.
1056 fanboysSocialBlockingListImageView.setEnabled(!isChecked);
1059 // Set the Fanboy's Social Blocking List switch listener.
1060 fanboysSocialBlockingListSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1061 // Update the icon color.
1062 fanboysSocialBlockingListImageView.setSelected(isChecked);
1065 // Set the UltraList switch listener.
1066 ultraListSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1067 // Update the icon color.
1068 ultraListImageView.setSelected(isChecked);
1071 // Set the UltraPrivacy switch listener.
1072 ultraPrivacySwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1073 // Update the icon color.
1074 ultraPrivacyImageView.setSelected(isChecked);
1077 // Set the block all third-party requests switch listener.
1078 blockAllThirdPartyRequestsSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1079 // Update the icon color.
1080 blockAllThirdPartyRequestsImageView.setSelected(isChecked);
1083 // Set the user agent spinner listener.
1084 userAgentSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1086 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1087 // Set the new user agent.
1089 case MainWebViewActivity.DOMAINS_SYSTEM_DEFAULT_USER_AGENT:
1090 // Show the user agent TextView.
1091 userAgentTextView.setVisibility(View.VISIBLE);
1093 // Hide the custom user agent EditText.
1094 customUserAgentEditText.setVisibility(View.GONE);
1096 // Set the user text.
1097 switch (defaultUserAgentArrayPosition) {
1098 case MainWebViewActivity.UNRECOGNIZED_USER_AGENT: // The default user agent name is not on the canonical list.
1099 // This is probably because it was set in an older version of Privacy Browser before the switch to persistent user agent names.
1100 userAgentTextView.setText(defaultUserAgentName);
1103 case MainWebViewActivity.SETTINGS_WEBVIEW_DEFAULT_USER_AGENT:
1104 // Display the `WebView` default user agent.
1105 userAgentTextView.setText(webViewDefaultUserAgentString);
1108 case MainWebViewActivity.SETTINGS_CUSTOM_USER_AGENT:
1109 // Display the custom user agent.
1110 userAgentTextView.setText(defaultCustomUserAgentString);
1114 // Get the user agent string from the user agent data array.
1115 userAgentTextView.setText(userAgentDataArray[defaultUserAgentArrayPosition]);
1119 case MainWebViewActivity.DOMAINS_WEBVIEW_DEFAULT_USER_AGENT:
1120 // Show the user agent TextView and set the text.
1121 userAgentTextView.setVisibility(View.VISIBLE);
1122 userAgentTextView.setText(webViewDefaultUserAgentString);
1124 // Hide the custom user agent EditTex.
1125 customUserAgentEditText.setVisibility(View.GONE);
1128 case MainWebViewActivity.DOMAINS_CUSTOM_USER_AGENT:
1129 // Hide the user agent TextView.
1130 userAgentTextView.setVisibility(View.GONE);
1132 // Show the custom user agent EditText and set the current user agent name as the text.
1133 customUserAgentEditText.setVisibility(View.VISIBLE);
1134 customUserAgentEditText.setText(currentUserAgentName);
1138 // 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.
1139 userAgentTextView.setVisibility(View.VISIBLE);
1140 userAgentTextView.setText(userAgentDataArray[position - 1]);
1142 // Hide `customUserAgentEditText`.
1143 customUserAgentEditText.setVisibility(View.GONE);
1148 public void onNothingSelected(AdapterView<?> parent) {
1153 // Set the X-Requested-With header spinner listener.
1154 xRequestedWithHeaderSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1156 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1157 // Update the icon and the visibility of the text view.
1159 case DomainsDatabaseHelper.SYSTEM_DEFAULT:
1160 // Set the icon color.
1161 xRequestedWithHeaderImageView.setSelected(defaultXRequestedWithHeader);
1163 // Show the X-Requested-With header text view.
1164 xRequestedWithHeaderTextView.setVisibility(View.VISIBLE);
1167 case DomainsDatabaseHelper.ENABLED:
1168 // Set the icon color.
1169 xRequestedWithHeaderImageView.setSelected(true);
1171 // Hide the X-Requested-With header text view.
1172 xRequestedWithHeaderTextView.setVisibility(View.GONE);
1175 case DomainsDatabaseHelper.DISABLED:
1176 // Set the icon color.
1177 xRequestedWithHeaderImageView.setSelected(false);
1179 // Hide the X-Requested-With header text view.
1180 xRequestedWithHeaderTextView.setVisibility(View.GONE);
1186 public void onNothingSelected(AdapterView<?> parent) {
1191 // Set the font size spinner listener.
1192 fontSizeSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1194 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1195 // Update the font size display options.
1196 if (position == 0) { // The system default font size has been selected.
1197 // Show the default font size text view.
1198 defaultFontSizeTextView.setVisibility(View.VISIBLE);
1200 // Hide the custom font size edit text.
1201 customFontSizeEditText.setVisibility(View.GONE);
1202 } else { // A custom font size has been selected.
1203 // Hide the default font size text view.
1204 defaultFontSizeTextView.setVisibility(View.GONE);
1206 // Show the custom font size edit text.
1207 customFontSizeEditText.setVisibility(View.VISIBLE);
1212 public void onNothingSelected(AdapterView<?> parent) {
1217 // Set the swipe to refresh spinner listener.
1218 swipeToRefreshSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1220 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1221 // Update the icon and the visibility of the text view.
1223 case DomainsDatabaseHelper.SYSTEM_DEFAULT:
1224 // Set the icon color.
1225 swipeToRefreshImageView.setSelected(defaultSwipeToRefresh);
1227 // Show the swipe to refresh text view.
1228 swipeToRefreshTextView.setVisibility(View.VISIBLE);
1231 case DomainsDatabaseHelper.ENABLED:
1232 // Set the icon color.
1233 swipeToRefreshImageView.setSelected(true);
1235 // Hide the swipe to refresh text view.
1236 swipeToRefreshTextView.setVisibility(View.GONE);
1239 case DomainsDatabaseHelper.DISABLED:
1240 // Set the icon color.
1241 swipeToRefreshImageView.setSelected(false);
1243 // Hide the swipe to refresh text view.
1244 swipeToRefreshTextView.setVisibility(View.GONE);
1249 public void onNothingSelected(AdapterView<?> parent) {
1254 // Set the WebView theme spinner listener.
1255 webViewThemeSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1257 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1258 // Update the icon and the visibility of the WebView theme text view.
1260 case DomainsDatabaseHelper.SYSTEM_DEFAULT: // the domain WebView theme is system default.
1261 // Set the icon according to the app WebView theme.
1262 switch (appWebViewThemeEntryNumber) {
1263 case DomainsDatabaseHelper.SYSTEM_DEFAULT: // The default WebView theme is system default.
1264 // Set the icon color.
1265 webViewThemeImageView.setSelected(currentThemeStatus == Configuration.UI_MODE_NIGHT_NO);
1268 case DomainsDatabaseHelper.LIGHT_THEME: // The default WebView theme is light.
1269 // Set the icon color.
1270 webViewThemeImageView.setSelected(true);
1273 case DomainsDatabaseHelper.DARK_THEME: // The default WebView theme is dark.
1275 webViewThemeImageView.setSelected(false);
1279 // Show the WebView theme text view.
1280 webViewThemeTextView.setVisibility(View.VISIBLE);
1283 case DomainsDatabaseHelper.LIGHT_THEME: // The domain WebView theme is light.
1284 // Set the icon color.
1285 webViewThemeImageView.setSelected(true);
1287 // Hide the WebView theme text view.
1288 webViewThemeTextView.setVisibility(View.GONE);
1291 case DomainsDatabaseHelper.DARK_THEME: // The domain WebView theme is dark.
1292 // Set the icon color.
1293 webViewThemeImageView.setSelected(false);
1295 // Hide the WebView theme text view.
1296 webViewThemeTextView.setVisibility(View.GONE);
1302 public void onNothingSelected(AdapterView<?> parent) {
1307 // Set the wide viewport spinner listener.
1308 wideViewportSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1310 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1311 // Update the icon and the visibility of the wide viewport text view.
1313 case DomainsDatabaseHelper.SYSTEM_DEFAULT:
1314 // Set the icon color.
1315 wideViewportImageView.setSelected(defaultWideViewport);
1317 // Show the wide viewport text view.
1318 wideViewportTextView.setVisibility(View.VISIBLE);
1321 case DomainsDatabaseHelper.ENABLED:
1322 // Set the icon color.
1323 wideViewportImageView.setSelected(true);
1325 // Hide the wide viewport text view.
1326 wideViewportTextView.setVisibility(View.GONE);
1329 case DomainsDatabaseHelper.DISABLED:
1330 // Set the icon color.
1331 wideViewportImageView.setSelected(false);
1333 // Hid ethe wide viewport text view.
1334 wideViewportTextView.setVisibility(View.GONE);
1340 public void onNothingSelected(AdapterView<?> parent) {
1345 // Set the display webpage images spinner listener.
1346 displayWebpageImagesSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1348 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1349 // Update the icon and the visibility of the display images text view.
1351 case DomainsDatabaseHelper.SYSTEM_DEFAULT:
1352 // Set the icon color.
1353 displayWebpageImagesImageView.setSelected(defaultDisplayWebpageImages);
1355 // Show the display images text view.
1356 displayImagesTextView.setVisibility(View.VISIBLE);
1359 case DomainsDatabaseHelper.ENABLED:
1360 // Set the icon color.
1361 displayWebpageImagesImageView.setSelected(true);
1363 // Hide the display images text view.
1364 displayImagesTextView.setVisibility(View.GONE);
1367 case DomainsDatabaseHelper.DISABLED:
1368 // Set the icon color.
1369 displayWebpageImagesImageView.setSelected(false);
1371 // Hide the display images text view.
1372 displayImagesTextView.setVisibility(View.GONE);
1378 public void onNothingSelected(AdapterView<?> parent) {
1383 // Set the pinned SSL certificate switch listener.
1384 pinnedSslCertificateSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1385 // Update the icon color.
1386 pinnedSslCertificateImageView.setSelected(isChecked);
1388 // Update the views.
1389 if (isChecked) { // SSL certificate pinning is enabled.
1390 // Update the visibility of the saved SSL certificate.
1391 if (savedSslIssuedToCNameString == null) {
1392 savedSslCardView.setVisibility(View.GONE);
1394 savedSslCardView.setVisibility(View.VISIBLE);
1397 // Update the visibility of the current website SSL certificate.
1398 if (DomainsActivity.sslIssuedToCName == null) {
1399 // Hide the SSL certificate.
1400 currentSslCardView.setVisibility(View.GONE);
1402 // Show the instruction.
1403 noCurrentWebsiteCertificateTextView.setVisibility(View.VISIBLE);
1405 // Show the SSL certificate.
1406 currentSslCardView.setVisibility(View.VISIBLE);
1408 // Hide the instruction.
1409 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
1412 // Set the status of the radio buttons.
1413 if (savedSslCardView.getVisibility() == View.VISIBLE) { // The saved SSL certificate is displayed.
1414 // Check the saved SSL certificate radio button.
1415 savedSslCertificateRadioButton.setChecked(true);
1417 // Uncheck the current website SSL certificate radio button.
1418 currentWebsiteCertificateRadioButton.setChecked(false);
1420 // Set the background of the saved SSL certificate linear layout to be transparent.
1421 savedSslCertificateLinearLayout.setBackgroundResource(R.color.transparent);
1423 // Darken the background of the current website SSL certificate linear layout according to the theme.
1424 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1425 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1427 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1430 // Scroll to the current website SSL certificate card.
1431 savedSslCardView.getParent().requestChildFocus(savedSslCardView, savedSslCardView);
1432 } else if (currentSslCardView.getVisibility() == View.VISIBLE) { // The saved SSL certificate is hidden but the current website SSL certificate is visible.
1433 // Check the current website SSL certificate radio button.
1434 currentWebsiteCertificateRadioButton.setChecked(true);
1436 // Uncheck the saved SSL certificate radio button.
1437 savedSslCertificateRadioButton.setChecked(false);
1439 // Set the background of the current website SSL certificate linear layout to be transparent.
1440 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.transparent);
1442 // Darken the background of the saved SSL certificate linear layout according to the theme.
1443 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1444 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1446 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1449 // Scroll to the current website SSL certificate card.
1450 currentSslCardView.getParent().requestChildFocus(currentSslCardView, currentSslCardView);
1451 } else { // Neither SSL certificate is visible.
1452 // Uncheck both radio buttons.
1453 savedSslCertificateRadioButton.setChecked(false);
1454 currentWebsiteCertificateRadioButton.setChecked(false);
1456 // Scroll to the current website SSL certificate card.
1457 noCurrentWebsiteCertificateTextView.getParent().requestChildFocus(noCurrentWebsiteCertificateTextView, noCurrentWebsiteCertificateTextView);
1459 } else { // SSL certificate pinning is disabled.
1460 // Hide the SSl certificates and instructions.
1461 savedSslCardView.setVisibility(View.GONE);
1462 currentSslCardView.setVisibility(View.GONE);
1463 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
1465 // Uncheck the radio buttons.
1466 savedSslCertificateRadioButton.setChecked(false);
1467 currentWebsiteCertificateRadioButton.setChecked(false);
1471 savedSslCardView.setOnClickListener((View view) -> {
1472 // Check the saved SSL certificate radio button.
1473 savedSslCertificateRadioButton.setChecked(true);
1475 // Uncheck the current website SSL certificate radio button.
1476 currentWebsiteCertificateRadioButton.setChecked(false);
1478 // Set the background of the saved SSL certificate linear layout to be transparent.
1479 savedSslCertificateLinearLayout.setBackgroundResource(R.color.transparent);
1481 // Darken the background of the current website SSL certificate linear layout according to the theme.
1482 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1483 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1485 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1489 savedSslCertificateRadioButton.setOnClickListener((View view) -> {
1490 // Check the saved SSL certificate radio button.
1491 savedSslCertificateRadioButton.setChecked(true);
1493 // Uncheck the current website SSL certificate radio button.
1494 currentWebsiteCertificateRadioButton.setChecked(false);
1496 // Set the background of the saved SSL certificate linear layout to be transparent.
1497 savedSslCertificateLinearLayout.setBackgroundResource(R.color.transparent);
1499 // Darken the background of the current website SSL certificate linear layout according to the theme.
1500 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1501 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1503 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1507 currentSslCardView.setOnClickListener((View view) -> {
1508 // Check the current website SSL certificate radio button.
1509 currentWebsiteCertificateRadioButton.setChecked(true);
1511 // Uncheck the saved SSL certificate radio button.
1512 savedSslCertificateRadioButton.setChecked(false);
1514 // Set the background of the current website SSL certificate linear layout to be transparent.
1515 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.transparent);
1517 // Darken the background of the saved SSL certificate linear layout according to the theme.
1518 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1519 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1521 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1525 currentWebsiteCertificateRadioButton.setOnClickListener((View view) -> {
1526 // Check the current website SSL certificate radio button.
1527 currentWebsiteCertificateRadioButton.setChecked(true);
1529 // Uncheck the saved SSL certificate radio button.
1530 savedSslCertificateRadioButton.setChecked(false);
1532 // Set the background of the current website SSL certificate linear layout to be transparent.
1533 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.transparent);
1535 // Darken the background of the saved SSL certificate linear layout according to the theme.
1536 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1537 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1539 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1543 // Set the pinned IP addresses switch listener.
1544 pinnedIpAddressesSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1545 // Update the icon color.
1546 pinnedIpAddressesImageView.setSelected(isChecked);
1548 // Update the views.
1549 if (isChecked) { // IP addresses pinning is enabled.
1550 // Update the visibility of the saved IP addresses card view.
1551 if (savedIpAddresses == null) { // There are no saved IP addresses.
1552 savedIpAddressesCardView.setVisibility(View.GONE);
1553 } else { // There are saved IP addresses.
1554 savedIpAddressesCardView.setVisibility(View.VISIBLE);
1557 // Show the current IP addresses card view.
1558 currentIpAddressesCardView.setVisibility(View.VISIBLE);
1560 // Set the status of the radio buttons.
1561 if (savedIpAddressesCardView.getVisibility() == View.VISIBLE) { // The saved IP addresses are visible.
1562 // Check the saved IP addresses radio button.
1563 savedIpAddressesRadioButton.setChecked(true);
1565 // Uncheck the current IP addresses radio button.
1566 currentIpAddressesRadioButton.setChecked(false);
1568 // Set the background of the saved IP addresses linear layout to be transparent.
1569 savedSslCertificateLinearLayout.setBackgroundResource(R.color.transparent);
1571 // Darken the background of the current IP addresses linear layout according to the theme.
1572 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1573 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1575 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1577 } else { // The saved IP addresses are not visible.
1578 // Check the current IP addresses radio button.
1579 currentIpAddressesRadioButton.setChecked(true);
1581 // Uncheck the saved IP addresses radio button.
1582 savedIpAddressesRadioButton.setChecked(false);
1584 // Set the background of the current IP addresses linear layout to be transparent.
1585 currentIpAddressesLinearLayout.setBackgroundResource(R.color.transparent);
1587 // Darken the background of the saved IP addresses linear layout according to the theme.
1588 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1589 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1591 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1595 // Scroll to the bottom of the card views.
1596 currentIpAddressesCardView.getParent().requestChildFocus(currentIpAddressesCardView, currentIpAddressesCardView);
1597 } else { // IP addresses pinning is disabled.
1598 // Hide the IP addresses card views.
1599 savedIpAddressesCardView.setVisibility(View.GONE);
1600 currentIpAddressesCardView.setVisibility(View.GONE);
1602 // Uncheck the radio buttons.
1603 savedIpAddressesRadioButton.setChecked(false);
1604 currentIpAddressesRadioButton.setChecked(false);
1608 savedIpAddressesCardView.setOnClickListener((View view) -> {
1609 // Check the saved IP addresses radio button.
1610 savedIpAddressesRadioButton.setChecked(true);
1612 // Uncheck the current website IP addresses radio button.
1613 currentIpAddressesRadioButton.setChecked(false);
1615 // Set the background of the saved IP addresses linear layout to be transparent.
1616 savedIpAddressesLinearLayout.setBackgroundResource(R.color.transparent);
1618 // Darken the background of the current IP addresses linear layout according to the theme.
1619 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1620 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1622 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1626 savedIpAddressesRadioButton.setOnClickListener((View view) -> {
1627 // Check the saved IP addresses radio button.
1628 savedIpAddressesRadioButton.setChecked(true);
1630 // Uncheck the current website IP addresses radio button.
1631 currentIpAddressesRadioButton.setChecked(false);
1633 // Set the background of the saved IP addresses linear layout to be transparent.
1634 savedIpAddressesLinearLayout.setBackgroundResource(R.color.transparent);
1636 // Darken the background of the current IP addresses linear layout according to the theme.
1637 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1638 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1640 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1644 currentIpAddressesCardView.setOnClickListener((View view) -> {
1645 // Check the current IP addresses radio button.
1646 currentIpAddressesRadioButton.setChecked(true);
1648 // Uncheck the saved IP addresses radio button.
1649 savedIpAddressesRadioButton.setChecked(false);
1651 // Set the background of the current IP addresses linear layout to be transparent.
1652 currentIpAddressesLinearLayout.setBackgroundResource(R.color.transparent);
1654 // Darken the background of the saved IP addresses linear layout according to the theme.
1655 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1656 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1658 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1662 currentIpAddressesRadioButton.setOnClickListener((View view) -> {
1663 // Check the current IP addresses radio button.
1664 currentIpAddressesRadioButton.setChecked(true);
1666 // Uncheck the saved IP addresses radio button.
1667 savedIpAddressesRadioButton.setChecked(false);
1669 // Set the background of the current IP addresses linear layout to be transparent.
1670 currentIpAddressesLinearLayout.setBackgroundResource(R.color.transparent);
1672 // Darken the background of the saved IP addresses linear layout according to the theme.
1673 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1674 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1676 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1680 // Set the scroll Y.
1681 domainSettingsScrollView.post(() -> domainSettingsScrollView.setScrollY(scrollY));
1683 // Return the domain settings view.
1684 return domainSettingsView;
1687 private boolean checkDomainNameAgainstCertificate(String domainName, String certificateCommonName) {
1688 // Initialize `domainNamesMatch`.
1689 boolean domainNamesMatch = false;
1691 // Check various wildcard permutations if `domainName` and `certificateCommonName` are not empty.
1692 // `noinspection ConstantCondition` removes Android Studio's incorrect lint warning that `domainName` can never be `null`.
1693 if ((domainName != null) && (certificateCommonName != null)) {
1694 // Check if the domains match.
1695 if (domainName.equals(certificateCommonName)) {
1696 domainNamesMatch = true;
1699 // If `domainName` starts with a wildcard, check the base domain against all the subdomains of `certificateCommonName`.
1700 if (!domainNamesMatch && domainName.startsWith("*.") && (domainName.length() > 2)) {
1701 // Remove the initial `*.`.
1702 String baseDomainName = domainName.substring(2);
1704 // Setup a copy of `certificateCommonName` to test subdomains.
1705 String certificateCommonNameSubdomain = certificateCommonName;
1707 // Check all the subdomains in `certificateCommonNameSubdomain` against `baseDomainName`.
1708 while (!domainNamesMatch && certificateCommonNameSubdomain.contains(".")) { // Stop checking if we know that `domainNamesMatch` is `true` or if we run out of `.`.
1709 // Test the `certificateCommonNameSubdomain` against `baseDomainName`.
1710 if (certificateCommonNameSubdomain.equals(baseDomainName)) {
1711 domainNamesMatch = true;
1714 // Strip out the lowest subdomain of `certificateCommonNameSubdomain`.
1716 certificateCommonNameSubdomain = certificateCommonNameSubdomain.substring(certificateCommonNameSubdomain.indexOf(".") + 1);
1717 } catch (IndexOutOfBoundsException e) { // `certificateCommonNameSubdomain` ends with `.`.
1718 certificateCommonNameSubdomain = "";
1723 // If `certificateCommonName` starts with a wildcard, check the base common name against all the subdomains of `domainName`.
1724 if (!domainNamesMatch && certificateCommonName.startsWith("*.") && (certificateCommonName.length() > 2)) {
1725 // Remove the initial `*.`.
1726 String baseCertificateCommonName = certificateCommonName.substring(2);
1728 // Setup a copy of `domainName` to test subdomains.
1729 String domainNameSubdomain = domainName;
1731 // Check all the subdomains in `domainNameSubdomain` against `baseCertificateCommonName`.
1732 while (!domainNamesMatch && domainNameSubdomain.contains(".") && (domainNameSubdomain.length() > 2)) {
1733 // Test the `domainNameSubdomain` against `baseCertificateCommonName`.
1734 if (domainNameSubdomain.equals(baseCertificateCommonName)) {
1735 domainNamesMatch = true;
1738 // Strip out the lowest subdomain of `domainNameSubdomain`.
1740 domainNameSubdomain = domainNameSubdomain.substring(domainNameSubdomain.indexOf(".") + 1);
1741 } catch (IndexOutOfBoundsException e) { // `domainNameSubdomain` ends with `.`.
1742 domainNameSubdomain = "";
1747 // If both names start with a wildcard, check if the root of one contains the root of the other.
1748 if (!domainNamesMatch && domainName.startsWith("*.") && (domainName.length() > 2) && certificateCommonName.startsWith("*.") && (certificateCommonName.length() > 2)) {
1749 // Remove the wildcards.
1750 String rootDomainName = domainName.substring(2);
1751 String rootCertificateCommonName = certificateCommonName.substring(2);
1753 // Check if one name ends with the contents of the other. If so, there will be overlap in the their wildcard subdomains.
1754 if (rootDomainName.endsWith(rootCertificateCommonName) || rootCertificateCommonName.endsWith(rootDomainName)) {
1755 domainNamesMatch = true;
1760 return domainNamesMatch;