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.
67 public static final String DATABASE_ID = "database_id";
68 public static final String SCROLL_Y = "scroll_y";
70 // Declare the public variables. `databaseId` is public static so it can be accessed from `DomainsActivity`.
71 public static int databaseId;
73 // Declare 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);
90 public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
91 // Inflate `domain_settings_fragment`. `false` does not attach it to the root `container`.
92 View domainSettingsView = inflater.inflate(R.layout.domain_settings_fragment, container, false);
94 // Get handles for the context and the resources.
95 Resources resources = getResources();
97 // Get the current theme status.
98 int currentThemeStatus = getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
100 // Get a handle for the shared preference.
101 SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(requireContext());
103 // Store the default settings.
104 String defaultUserAgentName = sharedPreferences.getString("user_agent", getString(R.string.user_agent_default_value));
105 String defaultCustomUserAgentString = sharedPreferences.getString("custom_user_agent", getString(R.string.custom_user_agent_default_value));
106 boolean defaultXRequestedWithHeader = sharedPreferences.getBoolean(getString(R.string.x_requested_with_header_key), true);
107 String defaultFontSizeString = sharedPreferences.getString("font_size", getString(R.string.font_size_default_value));
108 boolean defaultSwipeToRefresh = sharedPreferences.getBoolean("swipe_to_refresh", true);
109 String defaultWebViewTheme = sharedPreferences.getString("webview_theme", getString(R.string.webview_theme_default_value));
110 boolean defaultWideViewport = sharedPreferences.getBoolean("wide_viewport", true);
111 boolean defaultDisplayWebpageImages = sharedPreferences.getBoolean("display_webpage_images", true);
113 // Get handles for the views.
114 ScrollView domainSettingsScrollView = domainSettingsView.findViewById(R.id.domain_settings_scrollview);
115 EditText domainNameEditText = domainSettingsView.findViewById(R.id.domain_settings_name_edittext);
116 ImageView javaScriptImageView = domainSettingsView.findViewById(R.id.javascript_imageview);
117 SwitchCompat javaScriptSwitch = domainSettingsView.findViewById(R.id.javascript_switch);
118 ImageView cookiesImageView = domainSettingsView.findViewById(R.id.cookies_imageview);
119 SwitchCompat cookiesSwitch = domainSettingsView.findViewById(R.id.cookies_switch);
120 ImageView domStorageImageView = domainSettingsView.findViewById(R.id.dom_storage_imageview);
121 SwitchCompat domStorageSwitch = domainSettingsView.findViewById(R.id.dom_storage_switch);
122 ImageView formDataImageView = domainSettingsView.findViewById(R.id.form_data_imageview); // The form data views can be remove once the minimum API >= 26.
123 SwitchCompat formDataSwitch = domainSettingsView.findViewById(R.id.form_data_switch); // The form data views can be remove once the minimum API >= 26.
124 ImageView easyListImageView = domainSettingsView.findViewById(R.id.easylist_imageview);
125 SwitchCompat easyListSwitch = domainSettingsView.findViewById(R.id.easylist_switch);
126 ImageView easyPrivacyImageView = domainSettingsView.findViewById(R.id.easyprivacy_imageview);
127 SwitchCompat easyPrivacySwitch = domainSettingsView.findViewById(R.id.easyprivacy_switch);
128 ImageView fanboysAnnoyanceListImageView = domainSettingsView.findViewById(R.id.fanboys_annoyance_list_imageview);
129 SwitchCompat fanboysAnnoyanceListSwitch = domainSettingsView.findViewById(R.id.fanboys_annoyance_list_switch);
130 ImageView fanboysSocialBlockingListImageView = domainSettingsView.findViewById(R.id.fanboys_social_blocking_list_imageview);
131 SwitchCompat fanboysSocialBlockingListSwitch = domainSettingsView.findViewById(R.id.fanboys_social_blocking_list_switch);
132 ImageView ultraListImageView = domainSettingsView.findViewById(R.id.ultralist_imageview);
133 SwitchCompat ultraListSwitch = domainSettingsView.findViewById(R.id.ultralist_switch);
134 ImageView ultraPrivacyImageView = domainSettingsView.findViewById(R.id.ultraprivacy_imageview);
135 SwitchCompat ultraPrivacySwitch = domainSettingsView.findViewById(R.id.ultraprivacy_switch);
136 ImageView blockAllThirdPartyRequestsImageView = domainSettingsView.findViewById(R.id.block_all_third_party_requests_imageview);
137 SwitchCompat blockAllThirdPartyRequestsSwitch = domainSettingsView.findViewById(R.id.block_all_third_party_requests_switch);
138 Spinner userAgentSpinner = domainSettingsView.findViewById(R.id.user_agent_spinner);
139 TextView userAgentTextView = domainSettingsView.findViewById(R.id.user_agent_textview);
140 EditText customUserAgentEditText = domainSettingsView.findViewById(R.id.custom_user_agent_edittext);
141 ImageView xRequestedWithHeaderImageView = domainSettingsView.findViewById(R.id.x_requested_with_header_imageview);
142 Spinner xRequestedWithHeaderSpinner = domainSettingsView.findViewById(R.id.x_requested_with_header_spinner);
143 TextView xRequestedWithHeaderTextView = domainSettingsView.findViewById(R.id.x_requested_with_header_textview);
144 TextView xRequestedWithHeaderExplanationTextView = domainSettingsView.findViewById(R.id.x_requested_with_header_explanation_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 // Open the X-Requested-With header spinner when the explanation text view is clicked.
539 xRequestedWithHeaderExplanationTextView.setOnClickListener((View v) -> {
540 // Open the X-Requested header spinner.
541 xRequestedWithHeaderSpinner.performClick();
544 // Display the font size settings.
545 if (fontSizeInt == 0) { // `0` is the code for system default font size.
546 // Set the font size to the system default
547 fontSizeSpinner.setSelection(0);
549 // Show the default font size text view.
550 defaultFontSizeTextView.setVisibility(View.VISIBLE);
552 // Hide the custom font size edit text.
553 customFontSizeEditText.setVisibility(View.GONE);
555 // 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.
556 customFontSizeEditText.setText(defaultFontSizeString);
557 } else { // A custom font size is selected.
558 // Set the spinner to the custom font size.
559 fontSizeSpinner.setSelection(1);
561 // Hide the default font size text view.
562 defaultFontSizeTextView.setVisibility(View.GONE);
564 // Show the custom font size edit text.
565 customFontSizeEditText.setVisibility(View.GONE);
567 // Set the custom font size.
568 customFontSizeEditText.setText(String.valueOf(fontSizeInt));
571 // Initialize the default font size percentage string.
572 String defaultFontSizePercentageString = defaultFontSizeString + "%";
574 // Set the default font size text in the text view.
575 defaultFontSizeTextView.setText(defaultFontSizePercentageString);
577 // Open the font size spinner when the text view is clicked.
578 defaultFontSizeTextView.setOnClickListener((View v) -> {
579 // Open the user agent spinner.
580 fontSizeSpinner.performClick();
583 // Select the swipe to refresh selection in the spinner.
584 swipeToRefreshSpinner.setSelection(swipeToRefreshInt);
586 // Set the swipe to refresh text.
587 if (defaultSwipeToRefresh)
588 swipeToRefreshTextView.setText(swipeToRefreshArrayAdapter.getItem(DomainsDatabaseHelper.ENABLED));
590 swipeToRefreshTextView.setText(swipeToRefreshArrayAdapter.getItem(DomainsDatabaseHelper.DISABLED));
592 // Set the swipe to refresh icon and text view settings.
593 switch (swipeToRefreshInt) {
594 case DomainsDatabaseHelper.SYSTEM_DEFAULT:
595 // Set the icon color.
596 swipeToRefreshImageView.setSelected(defaultSwipeToRefresh);
598 // Show the swipe to refresh text view.
599 swipeToRefreshTextView.setVisibility(View.VISIBLE);
602 case DomainsDatabaseHelper.ENABLED:
603 // Set the icon color.
604 swipeToRefreshImageView.setSelected(true);
606 // Hide the swipe to refresh text view.
607 swipeToRefreshTextView.setVisibility(View.GONE);
610 case DomainsDatabaseHelper.DISABLED:
611 // Set the icon color.
612 swipeToRefreshImageView.setSelected(false);
614 // Hide the swipe to refresh text view.
615 swipeToRefreshTextView.setVisibility(View.GONE);
619 // Open the swipe to refresh spinner when the text view is clicked.
620 swipeToRefreshTextView.setOnClickListener((View v) -> {
621 // Open the swipe to refresh spinner.
622 swipeToRefreshSpinner.performClick();
625 // Get the WebView theme string arrays.
626 String[] webViewThemeStringArray = resources.getStringArray(R.array.webview_theme_array);
627 String[] webViewThemeEntryValuesStringArray = resources.getStringArray(R.array.webview_theme_entry_values);
629 // Define an app WebView theme entry number.
630 int appWebViewThemeEntryNumber;
632 // 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.
633 if (defaultWebViewTheme.equals(webViewThemeEntryValuesStringArray[1])) { // The light theme is selected.
634 // Store the default WebView theme entry number.
635 appWebViewThemeEntryNumber = 1;
636 } else if (defaultWebViewTheme.equals(webViewThemeEntryValuesStringArray[2])) { // The dark theme is selected.
637 // Store the default WebView theme entry number.
638 appWebViewThemeEntryNumber = 2;
639 } else { // The system default theme is selected.
640 // Store the default WebView theme entry number.
641 appWebViewThemeEntryNumber = 0;
644 // Select the WebView theme in the spinner.
645 webViewThemeSpinner.setSelection(webViewThemeInt);
647 // Set the WebView theme text.
648 if (appWebViewThemeEntryNumber == DomainsDatabaseHelper.SYSTEM_DEFAULT) { // The app WebView theme is system default.
649 // Set the text according to the current UI theme.
650 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) {
651 webViewThemeTextView.setText(webViewThemeStringArray[DomainsDatabaseHelper.LIGHT_THEME]);
653 webViewThemeTextView.setText(webViewThemeStringArray[DomainsDatabaseHelper.DARK_THEME]);
655 } else { // The app WebView theme is not system default.
656 // Set the text according to the app WebView theme.
657 webViewThemeTextView.setText(webViewThemeStringArray[appWebViewThemeEntryNumber]);
660 // Set the WebView theme icon and text visibility.
661 switch (webViewThemeInt) {
662 case DomainsDatabaseHelper.SYSTEM_DEFAULT: // The domain WebView theme is system default.
663 // Set the icon according to the app WebView theme.
664 switch (appWebViewThemeEntryNumber) {
665 case DomainsDatabaseHelper.SYSTEM_DEFAULT: // The default WebView theme is system default.
666 // Set the icon color.
667 webViewThemeImageView.setSelected(currentThemeStatus == Configuration.UI_MODE_NIGHT_NO);
670 case DomainsDatabaseHelper.LIGHT_THEME: // the default WebView theme is light.
671 // Set the icon color.
672 webViewThemeImageView.setSelected(true);
675 case DomainsDatabaseHelper.DARK_THEME: // the default WebView theme is dark.
676 // Set the icon color.
677 webViewThemeImageView.setSelected(false);
681 // Show the WebView theme text view.
682 webViewThemeTextView.setVisibility(View.VISIBLE);
685 case DomainsDatabaseHelper.LIGHT_THEME: // The domain WebView theme is light.
686 // Set the icon color.
687 webViewThemeImageView.setSelected(true);
689 // Hide the WebView theme text view.
690 webViewThemeTextView.setVisibility(View.GONE);
693 case DomainsDatabaseHelper.DARK_THEME: // The domain WebView theme is dark.
694 // Set the icon color.
695 webViewThemeImageView.setSelected(false);
697 // Hide the WebView theme text view.
698 webViewThemeTextView.setVisibility(View.GONE);
702 // Open the WebView theme spinner when the text view is clicked.
703 webViewThemeTextView.setOnClickListener((View v) -> {
704 // Open the WebView theme spinner.
705 webViewThemeSpinner.performClick();
708 // Select the wide viewport in the spinner.
709 wideViewportSpinner.setSelection(wideViewportInt);
711 // Set the default wide viewport text.
712 if (defaultWideViewport)
713 wideViewportTextView.setText(wideViewportArrayAdapter.getItem(DomainsDatabaseHelper.ENABLED));
715 wideViewportTextView.setText(wideViewportArrayAdapter.getItem(DomainsDatabaseHelper.DISABLED));
717 // Set the wide viewport icon and text view settings.
718 switch (wideViewportInt) {
719 case DomainsDatabaseHelper.SYSTEM_DEFAULT:
720 // Set the icon color.
721 wideViewportImageView.setSelected(defaultWideViewport);
723 // Show the wide viewport text view.
724 wideViewportTextView.setVisibility(View.VISIBLE);
727 case DomainsDatabaseHelper.ENABLED:
728 // Set the icon color.
729 wideViewportImageView.setSelected(true);
731 // Hide the wide viewport text view.
732 wideViewportTextView.setVisibility(View.GONE);
735 case DomainsDatabaseHelper.DISABLED:
736 // Set the icon color.
737 wideViewportImageView.setSelected(false);
739 // Hide the wide viewport text view.
740 wideViewportTextView.setVisibility(View.GONE);
744 // Open the wide viewport spinner when the text view is clicked.
745 wideViewportTextView.setOnClickListener((View view) -> {
746 // Open the wide viewport spinner.
747 wideViewportSpinner.performClick();
750 // Display the website images mode in the spinner.
751 displayWebpageImagesSpinner.setSelection(displayImagesInt);
753 // Set the default display images text.
754 if (defaultDisplayWebpageImages) {
755 displayImagesTextView.setText(displayImagesArrayAdapter.getItem(DomainsDatabaseHelper.ENABLED));
757 displayImagesTextView.setText(displayImagesArrayAdapter.getItem(DomainsDatabaseHelper.DISABLED));
760 // Set the display website images icon and text view settings.
761 switch (displayImagesInt) {
762 case DomainsDatabaseHelper.SYSTEM_DEFAULT:
763 // Set the icon color.
764 displayWebpageImagesImageView.setSelected(defaultDisplayWebpageImages);
766 // Show the display images text view.
767 displayImagesTextView.setVisibility(View.VISIBLE);
770 case DomainsDatabaseHelper.ENABLED:
771 // Set the icon color.
772 displayWebpageImagesImageView.setSelected(true);
774 // Hide the display images text view.
775 displayImagesTextView.setVisibility(View.GONE);
778 case DomainsDatabaseHelper.DISABLED:
779 // Set the icon color.
780 displayWebpageImagesImageView.setSelected(false);
782 // Hide the display images text view.
783 displayImagesTextView.setVisibility(View.GONE);
787 // Open the display images spinner when the text view is clicked.
788 displayImagesTextView.setOnClickListener((View view) -> {
789 // Open the user agent spinner.
790 displayWebpageImagesSpinner.performClick();
793 // Store the current date.
794 Date currentDate = Calendar.getInstance().getTime();
796 // Setup the string builders to display the general certificate information in blue. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
797 savedSslIssuedToONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), savedSslIssuedToONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
798 savedSslIssuedToUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), savedSslIssuedToUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
799 savedSslIssuedByCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), savedSslIssuedByCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
800 savedSslIssuedByONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), savedSslIssuedByONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
801 savedSslIssuedByUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), savedSslIssuedByUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
803 // Check the certificate Common Name against the domain name.
804 boolean savedSslCommonNameMatchesDomainName = checkDomainNameAgainstCertificate(domainNameString, savedSslIssuedToCNameString);
806 // Format the issued to Common Name color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
807 if (savedSslCommonNameMatchesDomainName) {
808 savedSslIssuedToCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), savedSslIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
810 savedSslIssuedToCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), savedSslIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
813 // Format the start date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
814 if ((savedSslStartDate != null) && savedSslStartDate.after(currentDate)) { // The certificate start date is in the future.
815 savedSslStartDateStringBuilder.setSpan(redColorSpan, startDateLabel.length(), savedSslStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
816 } else { // The certificate start date is in the past.
817 savedSslStartDateStringBuilder.setSpan(blueColorSpan, startDateLabel.length(), savedSslStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
820 // Format the end date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
821 if ((savedSslEndDate != null) && savedSslEndDate.before(currentDate)) { // The certificate end date is in the past.
822 savedSslEndDateStringBuilder.setSpan(redColorSpan, endDateLabel.length(), savedSslEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
823 } else { // The certificate end date is in the future.
824 savedSslEndDateStringBuilder.setSpan(blueColorSpan, endDateLabel.length(), savedSslEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
827 // Display the saved website SSL certificate strings.
828 savedSslIssuedToCNameTextView.setText(savedSslIssuedToCNameStringBuilder);
829 savedSslIssuedToONameTextView.setText(savedSslIssuedToONameStringBuilder);
830 savedSslIssuedToUNameTextView.setText(savedSslIssuedToUNameStringBuilder);
831 savedSslIssuedByCNameTextView.setText(savedSslIssuedByCNameStringBuilder);
832 savedSslIssuedByONameTextView.setText(savedSslIssuedByONameStringBuilder);
833 savedSslIssuedByUNameTextView.setText(savedSslIssuedByUNameStringBuilder);
834 savedSslStartDateTextView.setText(savedSslStartDateStringBuilder);
835 savedSslEndDateTextView.setText(savedSslEndDateStringBuilder);
837 // Populate the current website SSL certificate if there is one.
838 if (DomainsActivity.sslIssuedToCName != null) {
839 // Get dates from the raw long values.
840 Date currentSslStartDate = new Date(DomainsActivity.sslStartDateLong);
841 Date currentSslEndDate = new Date(DomainsActivity.sslEndDateLong);
843 // Create a spannable string builder for each text view that needs multiple colors of text.
844 SpannableStringBuilder currentSslIssuedToCNameStringBuilder = new SpannableStringBuilder(cNameLabel + DomainsActivity.sslIssuedToCName);
845 SpannableStringBuilder currentSslIssuedToONameStringBuilder = new SpannableStringBuilder(oNameLabel + DomainsActivity.sslIssuedToOName);
846 SpannableStringBuilder currentSslIssuedToUNameStringBuilder = new SpannableStringBuilder(uNameLabel + DomainsActivity.sslIssuedToUName);
847 SpannableStringBuilder currentSslIssuedByCNameStringBuilder = new SpannableStringBuilder(cNameLabel + DomainsActivity.sslIssuedByCName);
848 SpannableStringBuilder currentSslIssuedByONameStringBuilder = new SpannableStringBuilder(oNameLabel + DomainsActivity.sslIssuedByOName);
849 SpannableStringBuilder currentSslIssuedByUNameStringBuilder = new SpannableStringBuilder(uNameLabel + DomainsActivity.sslIssuedByUName);
850 SpannableStringBuilder currentSslStartDateStringBuilder = new SpannableStringBuilder(startDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG)
851 .format(currentSslStartDate));
852 SpannableStringBuilder currentSslEndDateStringBuilder = new SpannableStringBuilder(endDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG)
853 .format(currentSslEndDate));
855 // Setup the string builders to display the general certificate information in blue. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
856 currentSslIssuedToONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), currentSslIssuedToONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
857 currentSslIssuedToUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), currentSslIssuedToUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
858 currentSslIssuedByCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), currentSslIssuedByCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
859 currentSslIssuedByONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), currentSslIssuedByONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
860 currentSslIssuedByUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), currentSslIssuedByUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
862 // Check the certificate Common Name against the domain name.
863 boolean currentSslCommonNameMatchesDomainName = checkDomainNameAgainstCertificate(domainNameString, DomainsActivity.sslIssuedToCName);
865 // Format the issued to Common Name color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
866 if (currentSslCommonNameMatchesDomainName) {
867 currentSslIssuedToCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), currentSslIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
869 currentSslIssuedToCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), currentSslIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
872 // Format the start date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
873 if (currentSslStartDate.after(currentDate)) { // The certificate start date is in the future.
874 currentSslStartDateStringBuilder.setSpan(redColorSpan, startDateLabel.length(), currentSslStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
875 } else { // The certificate start date is in the past.
876 currentSslStartDateStringBuilder.setSpan(blueColorSpan, startDateLabel.length(), currentSslStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
879 // Format the end date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
880 if (currentSslEndDate.before(currentDate)) { // The certificate end date is in the past.
881 currentSslEndDateStringBuilder.setSpan(redColorSpan, endDateLabel.length(), currentSslEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
882 } else { // The certificate end date is in the future.
883 currentSslEndDateStringBuilder.setSpan(blueColorSpan, endDateLabel.length(), currentSslEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
886 // Display the current website SSL certificate strings.
887 currentSslIssuedToCNameTextView.setText(currentSslIssuedToCNameStringBuilder);
888 currentSslIssuedToONameTextView.setText(currentSslIssuedToONameStringBuilder);
889 currentSslIssuedToUNameTextView.setText(currentSslIssuedToUNameStringBuilder);
890 currentSslIssuedByCNameTextView.setText(currentSslIssuedByCNameStringBuilder);
891 currentSslIssuedByONameTextView.setText(currentSslIssuedByONameStringBuilder);
892 currentSslIssuedByUNameTextView.setText(currentSslIssuedByUNameStringBuilder);
893 currentSslStartDateTextView.setText(currentSslStartDateStringBuilder);
894 currentSslEndDateTextView.setText(currentSslEndDateStringBuilder);
897 // Set the initial display status of the SSL certificates card views.
898 if (pinnedSslCertificateSwitch.isChecked()) { // An SSL certificate is pinned.
899 // Set the visibility of the saved SSL certificate.
900 if (savedSslIssuedToCNameString == null) {
901 savedSslCardView.setVisibility(View.GONE);
903 savedSslCardView.setVisibility(View.VISIBLE);
906 // Set the visibility of the current website SSL certificate.
907 if (DomainsActivity.sslIssuedToCName == null) { // There is no current SSL certificate.
908 // Hide the SSL certificate.
909 currentSslCardView.setVisibility(View.GONE);
911 // Show the instruction.
912 noCurrentWebsiteCertificateTextView.setVisibility(View.VISIBLE);
913 } else { // There is a current SSL certificate.
914 // Show the SSL certificate.
915 currentSslCardView.setVisibility(View.VISIBLE);
917 // Hide the instruction.
918 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
921 // Set the status of the radio buttons and the card view backgrounds.
922 if (savedSslCardView.getVisibility() == View.VISIBLE) { // The saved SSL certificate is displayed.
923 // Check the saved SSL certificate radio button.
924 savedSslCertificateRadioButton.setChecked(true);
926 // Uncheck the current website SSL certificate radio button.
927 currentWebsiteCertificateRadioButton.setChecked(false);
929 // Darken the background of the current website SSL certificate linear layout according to the theme.
930 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
931 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
933 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
935 } else if (currentSslCardView.getVisibility() == View.VISIBLE) { // The saved SSL certificate is hidden but the current website SSL certificate is visible.
936 // Check the current website SSL certificate radio button.
937 currentWebsiteCertificateRadioButton.setChecked(true);
939 // Uncheck the saved SSL certificate radio button.
940 savedSslCertificateRadioButton.setChecked(false);
941 } else { // Neither SSL certificate is visible.
942 // Uncheck both radio buttons.
943 savedSslCertificateRadioButton.setChecked(false);
944 currentWebsiteCertificateRadioButton.setChecked(false);
946 } else { // An SSL certificate is not pinned.
947 // Hide the SSl certificates and instructions.
948 savedSslCardView.setVisibility(View.GONE);
949 currentSslCardView.setVisibility(View.GONE);
950 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
952 // Uncheck the radio buttons.
953 savedSslCertificateRadioButton.setChecked(false);
954 currentWebsiteCertificateRadioButton.setChecked(false);
957 // Populate the saved and current IP addresses.
958 savedIpAddressesTextView.setText(savedIpAddresses);
959 currentIpAddressesTextView.setText(DomainsActivity.currentIpAddresses);
961 // Set the initial display status of the IP addresses card views.
962 if (pinnedIpAddressesSwitch.isChecked()) { // IP addresses are pinned.
963 // Set the visibility of the saved IP addresses.
964 if (savedIpAddresses == null) { // There are no saved IP addresses.
965 savedIpAddressesCardView.setVisibility(View.GONE);
966 } else { // There are saved IP addresses.
967 savedIpAddressesCardView.setVisibility(View.VISIBLE);
970 // Set the visibility of the current IP addresses.
971 currentIpAddressesCardView.setVisibility(View.VISIBLE);
973 // Set the status of the radio buttons and the card view backgrounds.
974 if (savedIpAddressesCardView.getVisibility() == View.VISIBLE) { // The saved IP addresses are displayed.
975 // Check the saved IP addresses radio button.
976 savedIpAddressesRadioButton.setChecked(true);
978 // Uncheck the current IP addresses radio button.
979 currentIpAddressesRadioButton.setChecked(false);
981 // Darken the background of the current IP addresses linear layout according to the theme.
982 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
983 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
985 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
987 } else { // The saved IP addresses are hidden.
988 // Check the current IP addresses radio button.
989 currentIpAddressesRadioButton.setChecked(true);
991 // Uncheck the saved IP addresses radio button.
992 savedIpAddressesRadioButton.setChecked(false);
994 } else { // IP addresses are not pinned.
995 // Hide the IP addresses card views.
996 savedIpAddressesCardView.setVisibility(View.GONE);
997 currentIpAddressesCardView.setVisibility(View.GONE);
999 // Uncheck the radio buttons.
1000 savedIpAddressesRadioButton.setChecked(false);
1001 currentIpAddressesRadioButton.setChecked(false);
1005 // Set the JavaScript switch listener.
1006 javaScriptSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1007 // Update the JavaScript icon.
1009 javaScriptImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.javascript_enabled, null));
1011 javaScriptImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.privacy_mode, null));
1013 // Set the DOM storage switch status.
1014 domStorageSwitch.setEnabled(isChecked);
1016 // Set the DOM storage ghosted icon status.
1017 domStorageImageView.setEnabled(isChecked);
1020 // Set the cookies switch listener.
1021 cookiesSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1022 // Update the icon color.
1023 cookiesImageView.setSelected(isChecked);
1026 // Set the DOM Storage switch listener.
1027 domStorageSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1028 // Update the icon color.
1029 domStorageImageView.setSelected(isChecked);
1032 // Set the form data switch listener. It can be removed once the minimum API >= 26.
1033 if (Build.VERSION.SDK_INT < 26) {
1034 formDataSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1035 // Update the icon color.
1036 formDataImageView.setSelected(isChecked);
1040 // Set the EasyList switch listener.
1041 easyListSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1042 // Update the icon color.
1043 easyListImageView.setSelected(isChecked);
1046 // Set the EasyPrivacy switch listener.
1047 easyPrivacySwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1048 // Update the icon color.
1049 easyPrivacyImageView.setSelected(isChecked);
1052 // Set the Fanboy's Annoyance List switch listener.
1053 fanboysAnnoyanceListSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1054 // Update the icon color.
1055 fanboysAnnoyanceListImageView.setSelected(isChecked);
1058 // Set Fanboy's Social Blocking List switch position.
1059 fanboysSocialBlockingListSwitch.setEnabled(!isChecked);
1061 // Set the Social Blocking List icon ghosted status.
1062 fanboysSocialBlockingListImageView.setEnabled(!isChecked);
1065 // Set the Fanboy's Social Blocking List switch listener.
1066 fanboysSocialBlockingListSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1067 // Update the icon color.
1068 fanboysSocialBlockingListImageView.setSelected(isChecked);
1071 // Set the UltraList switch listener.
1072 ultraListSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1073 // Update the icon color.
1074 ultraListImageView.setSelected(isChecked);
1077 // Set the UltraPrivacy switch listener.
1078 ultraPrivacySwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1079 // Update the icon color.
1080 ultraPrivacyImageView.setSelected(isChecked);
1083 // Set the block all third-party requests switch listener.
1084 blockAllThirdPartyRequestsSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1085 // Update the icon color.
1086 blockAllThirdPartyRequestsImageView.setSelected(isChecked);
1089 // Set the user agent spinner listener.
1090 userAgentSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1092 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1093 // Set the new user agent.
1095 case MainWebViewActivity.DOMAINS_SYSTEM_DEFAULT_USER_AGENT:
1096 // Show the user agent TextView.
1097 userAgentTextView.setVisibility(View.VISIBLE);
1099 // Hide the custom user agent EditText.
1100 customUserAgentEditText.setVisibility(View.GONE);
1102 // Set the user text.
1103 switch (defaultUserAgentArrayPosition) {
1104 case MainWebViewActivity.UNRECOGNIZED_USER_AGENT: // The default user agent name is not on the canonical list.
1105 // This is probably because it was set in an older version of Privacy Browser before the switch to persistent user agent names.
1106 userAgentTextView.setText(defaultUserAgentName);
1109 case MainWebViewActivity.SETTINGS_WEBVIEW_DEFAULT_USER_AGENT:
1110 // Display the `WebView` default user agent.
1111 userAgentTextView.setText(webViewDefaultUserAgentString);
1114 case MainWebViewActivity.SETTINGS_CUSTOM_USER_AGENT:
1115 // Display the custom user agent.
1116 userAgentTextView.setText(defaultCustomUserAgentString);
1120 // Get the user agent string from the user agent data array.
1121 userAgentTextView.setText(userAgentDataArray[defaultUserAgentArrayPosition]);
1125 case MainWebViewActivity.DOMAINS_WEBVIEW_DEFAULT_USER_AGENT:
1126 // Show the user agent TextView and set the text.
1127 userAgentTextView.setVisibility(View.VISIBLE);
1128 userAgentTextView.setText(webViewDefaultUserAgentString);
1130 // Hide the custom user agent EditTex.
1131 customUserAgentEditText.setVisibility(View.GONE);
1134 case MainWebViewActivity.DOMAINS_CUSTOM_USER_AGENT:
1135 // Hide the user agent TextView.
1136 userAgentTextView.setVisibility(View.GONE);
1138 // Show the custom user agent EditText and set the current user agent name as the text.
1139 customUserAgentEditText.setVisibility(View.VISIBLE);
1140 customUserAgentEditText.setText(currentUserAgentName);
1144 // 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.
1145 userAgentTextView.setVisibility(View.VISIBLE);
1146 userAgentTextView.setText(userAgentDataArray[position - 1]);
1148 // Hide `customUserAgentEditText`.
1149 customUserAgentEditText.setVisibility(View.GONE);
1154 public void onNothingSelected(AdapterView<?> parent) {
1159 // Set the X-Requested-With header spinner listener.
1160 xRequestedWithHeaderSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1162 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1163 // Update the icon and the visibility of the text view.
1165 case DomainsDatabaseHelper.SYSTEM_DEFAULT:
1166 // Set the icon color.
1167 xRequestedWithHeaderImageView.setSelected(defaultXRequestedWithHeader);
1169 // Show the X-Requested-With header text view.
1170 xRequestedWithHeaderTextView.setVisibility(View.VISIBLE);
1173 case DomainsDatabaseHelper.ENABLED:
1174 // Set the icon color.
1175 xRequestedWithHeaderImageView.setSelected(true);
1177 // Hide the X-Requested-With header text view.
1178 xRequestedWithHeaderTextView.setVisibility(View.GONE);
1181 case DomainsDatabaseHelper.DISABLED:
1182 // Set the icon color.
1183 xRequestedWithHeaderImageView.setSelected(false);
1185 // Hide the X-Requested-With header text view.
1186 xRequestedWithHeaderTextView.setVisibility(View.GONE);
1192 public void onNothingSelected(AdapterView<?> parent) {
1197 // Set the font size spinner listener.
1198 fontSizeSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1200 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1201 // Update the font size display options.
1202 if (position == 0) { // The system default font size has been selected.
1203 // Show the default font size text view.
1204 defaultFontSizeTextView.setVisibility(View.VISIBLE);
1206 // Hide the custom font size edit text.
1207 customFontSizeEditText.setVisibility(View.GONE);
1208 } else { // A custom font size has been selected.
1209 // Hide the default font size text view.
1210 defaultFontSizeTextView.setVisibility(View.GONE);
1212 // Show the custom font size edit text.
1213 customFontSizeEditText.setVisibility(View.VISIBLE);
1218 public void onNothingSelected(AdapterView<?> parent) {
1223 // Set the swipe to refresh spinner listener.
1224 swipeToRefreshSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1226 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1227 // Update the icon and the visibility of the text view.
1229 case DomainsDatabaseHelper.SYSTEM_DEFAULT:
1230 // Set the icon color.
1231 swipeToRefreshImageView.setSelected(defaultSwipeToRefresh);
1233 // Show the swipe to refresh text view.
1234 swipeToRefreshTextView.setVisibility(View.VISIBLE);
1237 case DomainsDatabaseHelper.ENABLED:
1238 // Set the icon color.
1239 swipeToRefreshImageView.setSelected(true);
1241 // Hide the swipe to refresh text view.
1242 swipeToRefreshTextView.setVisibility(View.GONE);
1245 case DomainsDatabaseHelper.DISABLED:
1246 // Set the icon color.
1247 swipeToRefreshImageView.setSelected(false);
1249 // Hide the swipe to refresh text view.
1250 swipeToRefreshTextView.setVisibility(View.GONE);
1255 public void onNothingSelected(AdapterView<?> parent) {
1260 // Set the WebView theme spinner listener.
1261 webViewThemeSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1263 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1264 // Update the icon and the visibility of the WebView theme text view.
1266 case DomainsDatabaseHelper.SYSTEM_DEFAULT: // the domain WebView theme is system default.
1267 // Set the icon according to the app WebView theme.
1268 switch (appWebViewThemeEntryNumber) {
1269 case DomainsDatabaseHelper.SYSTEM_DEFAULT: // The default WebView theme is system default.
1270 // Set the icon color.
1271 webViewThemeImageView.setSelected(currentThemeStatus == Configuration.UI_MODE_NIGHT_NO);
1274 case DomainsDatabaseHelper.LIGHT_THEME: // The default WebView theme is light.
1275 // Set the icon color.
1276 webViewThemeImageView.setSelected(true);
1279 case DomainsDatabaseHelper.DARK_THEME: // The default WebView theme is dark.
1281 webViewThemeImageView.setSelected(false);
1285 // Show the WebView theme text view.
1286 webViewThemeTextView.setVisibility(View.VISIBLE);
1289 case DomainsDatabaseHelper.LIGHT_THEME: // The domain WebView theme is light.
1290 // Set the icon color.
1291 webViewThemeImageView.setSelected(true);
1293 // Hide the WebView theme text view.
1294 webViewThemeTextView.setVisibility(View.GONE);
1297 case DomainsDatabaseHelper.DARK_THEME: // The domain WebView theme is dark.
1298 // Set the icon color.
1299 webViewThemeImageView.setSelected(false);
1301 // Hide the WebView theme text view.
1302 webViewThemeTextView.setVisibility(View.GONE);
1308 public void onNothingSelected(AdapterView<?> parent) {
1313 // Set the wide viewport spinner listener.
1314 wideViewportSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1316 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1317 // Update the icon and the visibility of the wide viewport text view.
1319 case DomainsDatabaseHelper.SYSTEM_DEFAULT:
1320 // Set the icon color.
1321 wideViewportImageView.setSelected(defaultWideViewport);
1323 // Show the wide viewport text view.
1324 wideViewportTextView.setVisibility(View.VISIBLE);
1327 case DomainsDatabaseHelper.ENABLED:
1328 // Set the icon color.
1329 wideViewportImageView.setSelected(true);
1331 // Hide the wide viewport text view.
1332 wideViewportTextView.setVisibility(View.GONE);
1335 case DomainsDatabaseHelper.DISABLED:
1336 // Set the icon color.
1337 wideViewportImageView.setSelected(false);
1339 // Hid ethe wide viewport text view.
1340 wideViewportTextView.setVisibility(View.GONE);
1346 public void onNothingSelected(AdapterView<?> parent) {
1351 // Set the display webpage images spinner listener.
1352 displayWebpageImagesSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1354 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1355 // Update the icon and the visibility of the display images text view.
1357 case DomainsDatabaseHelper.SYSTEM_DEFAULT:
1358 // Set the icon color.
1359 displayWebpageImagesImageView.setSelected(defaultDisplayWebpageImages);
1361 // Show the display images text view.
1362 displayImagesTextView.setVisibility(View.VISIBLE);
1365 case DomainsDatabaseHelper.ENABLED:
1366 // Set the icon color.
1367 displayWebpageImagesImageView.setSelected(true);
1369 // Hide the display images text view.
1370 displayImagesTextView.setVisibility(View.GONE);
1373 case DomainsDatabaseHelper.DISABLED:
1374 // Set the icon color.
1375 displayWebpageImagesImageView.setSelected(false);
1377 // Hide the display images text view.
1378 displayImagesTextView.setVisibility(View.GONE);
1384 public void onNothingSelected(AdapterView<?> parent) {
1389 // Set the pinned SSL certificate switch listener.
1390 pinnedSslCertificateSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1391 // Update the icon color.
1392 pinnedSslCertificateImageView.setSelected(isChecked);
1394 // Update the views.
1395 if (isChecked) { // SSL certificate pinning is enabled.
1396 // Update the visibility of the saved SSL certificate.
1397 if (savedSslIssuedToCNameString == null) {
1398 savedSslCardView.setVisibility(View.GONE);
1400 savedSslCardView.setVisibility(View.VISIBLE);
1403 // Update the visibility of the current website SSL certificate.
1404 if (DomainsActivity.sslIssuedToCName == null) {
1405 // Hide the SSL certificate.
1406 currentSslCardView.setVisibility(View.GONE);
1408 // Show the instruction.
1409 noCurrentWebsiteCertificateTextView.setVisibility(View.VISIBLE);
1411 // Show the SSL certificate.
1412 currentSslCardView.setVisibility(View.VISIBLE);
1414 // Hide the instruction.
1415 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
1418 // Set the status of the radio buttons.
1419 if (savedSslCardView.getVisibility() == View.VISIBLE) { // The saved SSL certificate is displayed.
1420 // Check the saved SSL certificate radio button.
1421 savedSslCertificateRadioButton.setChecked(true);
1423 // Uncheck the current website SSL certificate radio button.
1424 currentWebsiteCertificateRadioButton.setChecked(false);
1426 // Set the background of the saved SSL certificate linear layout to be transparent.
1427 savedSslCertificateLinearLayout.setBackgroundResource(R.color.transparent);
1429 // Darken the background of the current website SSL certificate linear layout according to the theme.
1430 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1431 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1433 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1436 // Scroll to the current website SSL certificate card.
1437 savedSslCardView.getParent().requestChildFocus(savedSslCardView, savedSslCardView);
1438 } else if (currentSslCardView.getVisibility() == View.VISIBLE) { // The saved SSL certificate is hidden but the current website SSL certificate is visible.
1439 // Check the current website SSL certificate radio button.
1440 currentWebsiteCertificateRadioButton.setChecked(true);
1442 // Uncheck the saved SSL certificate radio button.
1443 savedSslCertificateRadioButton.setChecked(false);
1445 // Set the background of the current website SSL certificate linear layout to be transparent.
1446 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.transparent);
1448 // Darken the background of the saved SSL certificate linear layout according to the theme.
1449 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1450 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1452 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1455 // Scroll to the current website SSL certificate card.
1456 currentSslCardView.getParent().requestChildFocus(currentSslCardView, currentSslCardView);
1457 } else { // Neither SSL certificate is visible.
1458 // Uncheck both radio buttons.
1459 savedSslCertificateRadioButton.setChecked(false);
1460 currentWebsiteCertificateRadioButton.setChecked(false);
1462 // Scroll to the current website SSL certificate card.
1463 noCurrentWebsiteCertificateTextView.getParent().requestChildFocus(noCurrentWebsiteCertificateTextView, noCurrentWebsiteCertificateTextView);
1465 } else { // SSL certificate pinning is disabled.
1466 // Hide the SSl certificates and instructions.
1467 savedSslCardView.setVisibility(View.GONE);
1468 currentSslCardView.setVisibility(View.GONE);
1469 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
1471 // Uncheck the radio buttons.
1472 savedSslCertificateRadioButton.setChecked(false);
1473 currentWebsiteCertificateRadioButton.setChecked(false);
1477 savedSslCardView.setOnClickListener((View view) -> {
1478 // Check the saved SSL certificate radio button.
1479 savedSslCertificateRadioButton.setChecked(true);
1481 // Uncheck the current website SSL certificate radio button.
1482 currentWebsiteCertificateRadioButton.setChecked(false);
1484 // Set the background of the saved SSL certificate linear layout to be transparent.
1485 savedSslCertificateLinearLayout.setBackgroundResource(R.color.transparent);
1487 // Darken the background of the current website SSL certificate linear layout according to the theme.
1488 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1489 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1491 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1495 savedSslCertificateRadioButton.setOnClickListener((View view) -> {
1496 // Check the saved SSL certificate radio button.
1497 savedSslCertificateRadioButton.setChecked(true);
1499 // Uncheck the current website SSL certificate radio button.
1500 currentWebsiteCertificateRadioButton.setChecked(false);
1502 // Set the background of the saved SSL certificate linear layout to be transparent.
1503 savedSslCertificateLinearLayout.setBackgroundResource(R.color.transparent);
1505 // Darken the background of the current website SSL certificate linear layout according to the theme.
1506 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1507 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1509 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1513 currentSslCardView.setOnClickListener((View view) -> {
1514 // Check the current website SSL certificate radio button.
1515 currentWebsiteCertificateRadioButton.setChecked(true);
1517 // Uncheck the saved SSL certificate radio button.
1518 savedSslCertificateRadioButton.setChecked(false);
1520 // Set the background of the current website SSL certificate linear layout to be transparent.
1521 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.transparent);
1523 // Darken the background of the saved SSL certificate linear layout according to the theme.
1524 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1525 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1527 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1531 currentWebsiteCertificateRadioButton.setOnClickListener((View view) -> {
1532 // Check the current website SSL certificate radio button.
1533 currentWebsiteCertificateRadioButton.setChecked(true);
1535 // Uncheck the saved SSL certificate radio button.
1536 savedSslCertificateRadioButton.setChecked(false);
1538 // Set the background of the current website SSL certificate linear layout to be transparent.
1539 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.transparent);
1541 // Darken the background of the saved SSL certificate linear layout according to the theme.
1542 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1543 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1545 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1549 // Set the pinned IP addresses switch listener.
1550 pinnedIpAddressesSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1551 // Update the icon color.
1552 pinnedIpAddressesImageView.setSelected(isChecked);
1554 // Update the views.
1555 if (isChecked) { // IP addresses pinning is enabled.
1556 // Update the visibility of the saved IP addresses card view.
1557 if (savedIpAddresses == null) { // There are no saved IP addresses.
1558 savedIpAddressesCardView.setVisibility(View.GONE);
1559 } else { // There are saved IP addresses.
1560 savedIpAddressesCardView.setVisibility(View.VISIBLE);
1563 // Show the current IP addresses card view.
1564 currentIpAddressesCardView.setVisibility(View.VISIBLE);
1566 // Set the status of the radio buttons.
1567 if (savedIpAddressesCardView.getVisibility() == View.VISIBLE) { // The saved IP addresses are visible.
1568 // Check the saved IP addresses radio button.
1569 savedIpAddressesRadioButton.setChecked(true);
1571 // Uncheck the current IP addresses radio button.
1572 currentIpAddressesRadioButton.setChecked(false);
1574 // Set the background of the saved IP addresses linear layout to be transparent.
1575 savedSslCertificateLinearLayout.setBackgroundResource(R.color.transparent);
1577 // Darken the background of the current IP addresses linear layout according to the theme.
1578 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1579 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1581 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1583 } else { // The saved IP addresses are not visible.
1584 // Check the current IP addresses radio button.
1585 currentIpAddressesRadioButton.setChecked(true);
1587 // Uncheck the saved IP addresses radio button.
1588 savedIpAddressesRadioButton.setChecked(false);
1590 // Set the background of the current IP addresses linear layout to be transparent.
1591 currentIpAddressesLinearLayout.setBackgroundResource(R.color.transparent);
1593 // Darken the background of the saved IP addresses linear layout according to the theme.
1594 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1595 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1597 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1601 // Scroll to the bottom of the card views.
1602 currentIpAddressesCardView.getParent().requestChildFocus(currentIpAddressesCardView, currentIpAddressesCardView);
1603 } else { // IP addresses pinning is disabled.
1604 // Hide the IP addresses card views.
1605 savedIpAddressesCardView.setVisibility(View.GONE);
1606 currentIpAddressesCardView.setVisibility(View.GONE);
1608 // Uncheck the radio buttons.
1609 savedIpAddressesRadioButton.setChecked(false);
1610 currentIpAddressesRadioButton.setChecked(false);
1614 savedIpAddressesCardView.setOnClickListener((View view) -> {
1615 // Check the saved IP addresses radio button.
1616 savedIpAddressesRadioButton.setChecked(true);
1618 // Uncheck the current website IP addresses radio button.
1619 currentIpAddressesRadioButton.setChecked(false);
1621 // Set the background of the saved IP addresses linear layout to be transparent.
1622 savedIpAddressesLinearLayout.setBackgroundResource(R.color.transparent);
1624 // Darken the background of the current IP addresses linear layout according to the theme.
1625 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1626 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1628 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1632 savedIpAddressesRadioButton.setOnClickListener((View view) -> {
1633 // Check the saved IP addresses radio button.
1634 savedIpAddressesRadioButton.setChecked(true);
1636 // Uncheck the current website IP addresses radio button.
1637 currentIpAddressesRadioButton.setChecked(false);
1639 // Set the background of the saved IP addresses linear layout to be transparent.
1640 savedIpAddressesLinearLayout.setBackgroundResource(R.color.transparent);
1642 // Darken the background of the current IP addresses linear layout according to the theme.
1643 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1644 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1646 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1650 currentIpAddressesCardView.setOnClickListener((View view) -> {
1651 // Check the current IP addresses radio button.
1652 currentIpAddressesRadioButton.setChecked(true);
1654 // Uncheck the saved IP addresses radio button.
1655 savedIpAddressesRadioButton.setChecked(false);
1657 // Set the background of the current IP addresses linear layout to be transparent.
1658 currentIpAddressesLinearLayout.setBackgroundResource(R.color.transparent);
1660 // Darken the background of the saved IP addresses linear layout according to the theme.
1661 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1662 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1664 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1668 currentIpAddressesRadioButton.setOnClickListener((View view) -> {
1669 // Check the current IP addresses radio button.
1670 currentIpAddressesRadioButton.setChecked(true);
1672 // Uncheck the saved IP addresses radio button.
1673 savedIpAddressesRadioButton.setChecked(false);
1675 // Set the background of the current IP addresses linear layout to be transparent.
1676 currentIpAddressesLinearLayout.setBackgroundResource(R.color.transparent);
1678 // Darken the background of the saved IP addresses linear layout according to the theme.
1679 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1680 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1682 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1686 // Set the scroll Y.
1687 domainSettingsScrollView.post(() -> domainSettingsScrollView.setScrollY(scrollY));
1689 // Return the domain settings view.
1690 return domainSettingsView;
1693 private boolean checkDomainNameAgainstCertificate(String domainName, String certificateCommonName) {
1694 // Initialize `domainNamesMatch`.
1695 boolean domainNamesMatch = false;
1697 // Check various wildcard permutations if `domainName` and `certificateCommonName` are not empty.
1698 // `noinspection ConstantCondition` removes Android Studio's incorrect lint warning that `domainName` can never be `null`.
1699 if ((domainName != null) && (certificateCommonName != null)) {
1700 // Check if the domains match.
1701 if (domainName.equals(certificateCommonName)) {
1702 domainNamesMatch = true;
1705 // If `domainName` starts with a wildcard, check the base domain against all the subdomains of `certificateCommonName`.
1706 if (!domainNamesMatch && domainName.startsWith("*.") && (domainName.length() > 2)) {
1707 // Remove the initial `*.`.
1708 String baseDomainName = domainName.substring(2);
1710 // Setup a copy of `certificateCommonName` to test subdomains.
1711 String certificateCommonNameSubdomain = certificateCommonName;
1713 // Check all the subdomains in `certificateCommonNameSubdomain` against `baseDomainName`.
1714 while (!domainNamesMatch && certificateCommonNameSubdomain.contains(".")) { // Stop checking if we know that `domainNamesMatch` is `true` or if we run out of `.`.
1715 // Test the `certificateCommonNameSubdomain` against `baseDomainName`.
1716 if (certificateCommonNameSubdomain.equals(baseDomainName)) {
1717 domainNamesMatch = true;
1720 // Strip out the lowest subdomain of `certificateCommonNameSubdomain`.
1722 certificateCommonNameSubdomain = certificateCommonNameSubdomain.substring(certificateCommonNameSubdomain.indexOf(".") + 1);
1723 } catch (IndexOutOfBoundsException e) { // `certificateCommonNameSubdomain` ends with `.`.
1724 certificateCommonNameSubdomain = "";
1729 // If `certificateCommonName` starts with a wildcard, check the base common name against all the subdomains of `domainName`.
1730 if (!domainNamesMatch && certificateCommonName.startsWith("*.") && (certificateCommonName.length() > 2)) {
1731 // Remove the initial `*.`.
1732 String baseCertificateCommonName = certificateCommonName.substring(2);
1734 // Setup a copy of `domainName` to test subdomains.
1735 String domainNameSubdomain = domainName;
1737 // Check all the subdomains in `domainNameSubdomain` against `baseCertificateCommonName`.
1738 while (!domainNamesMatch && domainNameSubdomain.contains(".") && (domainNameSubdomain.length() > 2)) {
1739 // Test the `domainNameSubdomain` against `baseCertificateCommonName`.
1740 if (domainNameSubdomain.equals(baseCertificateCommonName)) {
1741 domainNamesMatch = true;
1744 // Strip out the lowest subdomain of `domainNameSubdomain`.
1746 domainNameSubdomain = domainNameSubdomain.substring(domainNameSubdomain.indexOf(".") + 1);
1747 } catch (IndexOutOfBoundsException e) { // `domainNameSubdomain` ends with `.`.
1748 domainNameSubdomain = "";
1753 // If both names start with a wildcard, check if the root of one contains the root of the other.
1754 if (!domainNamesMatch && domainName.startsWith("*.") && (domainName.length() > 2) && certificateCommonName.startsWith("*.") && (certificateCommonName.length() > 2)) {
1755 // Remove the wildcards.
1756 String rootDomainName = domainName.substring(2);
1757 String rootCertificateCommonName = certificateCommonName.substring(2);
1759 // Check if one name ends with the contents of the other. If so, there will be overlap in the their wildcard subdomains.
1760 if (rootDomainName.endsWith(rootCertificateCommonName) || rootCertificateCommonName.endsWith(rootDomainName)) {
1761 domainNamesMatch = true;
1766 return domainNamesMatch;