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 JavaScript switch status.
367 if (javaScriptInt == 1) { // JavaScript is enabled.
368 javaScriptSwitch.setChecked(true);
369 javaScriptImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.javascript_enabled, null));
370 } else { // JavaScript is disabled.
371 javaScriptSwitch.setChecked(false);
372 javaScriptImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.privacy_mode, null));
375 // Set the cookies switch status. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
376 // Doing this makes no sense until it can also be done with the preferences.
377 if (cookiesInt == 1) { // Cookies are enabled.
378 // Turn the switch on.
379 cookiesSwitch.setChecked(true);
382 cookiesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.cookies_enabled, null));
383 } else { // Cookies are disabled.
384 // Turn the switch off
385 cookiesSwitch.setChecked(false);
388 cookiesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.cookies_disabled, null));
391 // Only enable DOM storage if JavaScript is enabled.
392 if (javaScriptInt == 1) { // JavaScript is enabled.
393 // Enable the DOM storage switch.
394 domStorageSwitch.setEnabled(true);
396 // Set the DOM storage status. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
397 // Doing this makes no sense until it can also be done with the preferences.
398 if (domStorageInt == 1) { // Both JavaScript and DOM storage are enabled.
399 domStorageSwitch.setChecked(true);
400 domStorageImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.dom_storage_enabled, null));
401 } else { // JavaScript is enabled but DOM storage is disabled.
402 // Set the DOM storage switch to off.
403 domStorageSwitch.setChecked(false);
406 domStorageImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.dom_storage_disabled, null));
408 } else { // JavaScript is disabled.
409 // Disable the DOM storage switch.
410 domStorageSwitch.setEnabled(false);
412 // Set the checked status of DOM storage.
413 domStorageSwitch.setChecked(domStorageInt == 1);
416 domStorageImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.dom_storage_ghosted, null));
419 // Set the form data visibility. Form data can be removed once the minimum API >= 26.
420 if (Build.VERSION.SDK_INT >= 26) { // Form data no longer applies to newer versions of Android.
421 // Hide the form data image view and switch.
422 formDataImageView.setVisibility(View.GONE);
423 formDataSwitch.setVisibility(View.GONE);
424 } else { // Form data should be displayed because this is an older version of Android.
425 if (formDataInt == 1) { // Form data is on.
426 // Turn the form data switch on.
427 formDataSwitch.setChecked(true);
429 // Set the form data icon.
430 formDataImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.form_data_enabled, null));
431 } else { // Form data is off.
432 // Turn the form data switch to off.
433 formDataSwitch.setChecked(false);
435 // Set the icon. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
436 // Doing this makes no sense until it can also be done with the preferences.
437 formDataImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.form_data_disabled, null));
441 // Set the switch positions.
442 easyListSwitch.setChecked(easyListInt == 1);
443 easyPrivacySwitch.setChecked(easyPrivacyInt == 1);
444 fanboysAnnoyanceListSwitch.setChecked(fanboysAnnoyanceListInt == 1);
445 fanboysSocialBlockingListSwitch.setChecked(fanboysSocialBlockingListInt == 1);
446 ultraListSwitch.setChecked(ultraListInt == 1);
447 ultraPrivacySwitch.setChecked(ultraPrivacyInt == 1);
448 blockAllThirdPartyRequestsSwitch.setChecked(blockAllThirdPartyRequestsInt == 1);
450 // Set the switch icon colors.
451 easyListImageView.setSelected(easyListInt == 1);
452 easyPrivacyImageView.setSelected(easyPrivacyInt == 1);
453 fanboysAnnoyanceListImageView.setSelected(fanboysAnnoyanceListInt == 1);
454 fanboysSocialBlockingListImageView.setSelected(fanboysSocialBlockingListInt == 1);
455 ultraListImageView.setSelected(ultraListInt == 1);
456 ultraPrivacyImageView.setSelected(ultraPrivacyInt == 1);
457 blockAllThirdPartyRequestsImageView.setSelected(blockAllThirdPartyRequestsInt == 1);
459 // Set Fanboy's Social Blocking List switch status based on the Annoyance List status.
460 fanboysSocialBlockingListSwitch.setEnabled(fanboysAnnoyanceListInt == 0);
462 // Set the Social Blocking List icon ghosted status based on the Annoyance List status.
463 fanboysSocialBlockingListImageView.setEnabled(fanboysAnnoyanceListInt == 0);
465 // Inflated a WebView to get the default user agent.
466 // `@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.
467 @SuppressLint("InflateParams") View bareWebViewLayout = inflater.inflate(R.layout.bare_webview, null, false);
468 WebView bareWebView = bareWebViewLayout.findViewById(R.id.bare_webview);
469 final String webViewDefaultUserAgentString = bareWebView.getSettings().getUserAgentString();
471 // Get a handle for the user agent array adapter. This array does not contain the `System default` entry.
472 ArrayAdapter<CharSequence> userAgentNamesArray = ArrayAdapter.createFromResource(requireContext(), R.array.user_agent_names, R.layout.spinner_item);
474 // Get the positions of the user agent and the default user agent.
475 int userAgentArrayPosition = userAgentNamesArray.getPosition(currentUserAgentName);
476 int defaultUserAgentArrayPosition = userAgentNamesArray.getPosition(defaultUserAgentName);
478 // Get a handle for the user agent data array. This array does not contain the `System default` entry.
479 String[] userAgentDataArray = resources.getStringArray(R.array.user_agent_data);
481 // Set the user agent text.
482 if (currentUserAgentName.equals(getString(R.string.system_default_user_agent))) { // Use the system default user agent.
483 // Set the user agent according to the system default.
484 switch (defaultUserAgentArrayPosition) {
485 case MainWebViewActivity.UNRECOGNIZED_USER_AGENT: // The default user agent name is not on the canonical list.
486 // This is probably because it was set in an older version of Privacy Browser before the switch to persistent user agent names.
487 userAgentTextView.setText(defaultUserAgentName);
490 case MainWebViewActivity.SETTINGS_WEBVIEW_DEFAULT_USER_AGENT:
491 // Display the `WebView` default user agent.
492 userAgentTextView.setText(webViewDefaultUserAgentString);
495 case MainWebViewActivity.SETTINGS_CUSTOM_USER_AGENT:
496 // Display the custom user agent.
497 userAgentTextView.setText(defaultCustomUserAgentString);
501 // Get the user agent string from the user agent data array.
502 userAgentTextView.setText(userAgentDataArray[defaultUserAgentArrayPosition]);
504 } else if (userAgentArrayPosition == MainWebViewActivity.UNRECOGNIZED_USER_AGENT || currentUserAgentName.equals(getString(R.string.custom_user_agent))) {
505 // 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.
506 // Set the user agent spinner to `Custom user agent`.
507 userAgentSpinner.setSelection(MainWebViewActivity.DOMAINS_CUSTOM_USER_AGENT);
509 // Hide the user agent TextView.
510 userAgentTextView.setVisibility(View.GONE);
512 // Show the custom user agent EditText and set the current user agent name as the text.
513 customUserAgentEditText.setVisibility(View.VISIBLE);
514 customUserAgentEditText.setText(currentUserAgentName);
515 } else { // The user agent name contains one of the canonical user agents.
516 // 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.
517 userAgentSpinner.setSelection(userAgentArrayPosition + 1);
519 // Show the user agent TextView.
520 userAgentTextView.setVisibility(View.VISIBLE);
522 // Hide the custom user agent EditText.
523 customUserAgentEditText.setVisibility(View.GONE);
525 // Set the user agent text.
526 if (userAgentArrayPosition == MainWebViewActivity.DOMAINS_WEBVIEW_DEFAULT_USER_AGENT) { // The WebView default user agent is selected.
527 // Display the WebView default user agent.
528 userAgentTextView.setText(webViewDefaultUserAgentString);
529 } else { // A user agent besides the default is selected.
530 // 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.
531 userAgentTextView.setText(userAgentDataArray[userAgentArrayPosition + 1]);
535 // Open the user agent spinner when the text view is clicked.
536 userAgentTextView.setOnClickListener((View v) -> {
537 // Open the user agent spinner.
538 userAgentSpinner.performClick();
541 // Select the X-Requested-With header selection in the spinner.
542 xRequestedWithHeaderSpinner.setSelection(xRequestedWithHeaderInt);
544 // Set the X-Requested-With header text.
545 if (defaultXRequestedWithHeader)
546 xRequestedWithHeaderTextView.setText(xRequestedWithHeaderArrayAdapter.getItem(DomainsDatabaseHelper.ENABLED));
548 xRequestedWithHeaderTextView.setText(xRequestedWithHeaderArrayAdapter.getItem(DomainsDatabaseHelper.DISABLED));
550 // Set the X-Requested-With header icon and text view settings.
551 switch (xRequestedWithHeaderInt) {
552 case DomainsDatabaseHelper.SYSTEM_DEFAULT:
553 // Set the icon color.
554 xRequestedWithHeaderImageView.setSelected(defaultXRequestedWithHeader);
556 // Show the X-Requested-With header text view.
557 xRequestedWithHeaderTextView.setVisibility(View.VISIBLE);
560 case DomainsDatabaseHelper.ENABLED:
561 // Set the icon color.
562 xRequestedWithHeaderImageView.setSelected(true);
564 // Hide the X-Requested-With header text view.
565 xRequestedWithHeaderTextView.setVisibility(View.GONE);
568 case DomainsDatabaseHelper.DISABLED:
569 // Set the icon color.
570 xRequestedWithHeaderImageView.setSelected(false);
572 // Hide the X-Requested-With header text view.
573 xRequestedWithHeaderTextView.setVisibility(View.GONE);
577 // Open the X-Requested-With header spinner when the text view is clicked.
578 xRequestedWithHeaderTextView.setOnClickListener((View v) -> {
579 // Open the X-Requested-With header spinner.
580 xRequestedWithHeaderSpinner.performClick();
583 // Display the font size settings.
584 if (fontSizeInt == 0) { // `0` is the code for system default font size.
585 // Set the font size to the system default
586 fontSizeSpinner.setSelection(0);
588 // Show the default font size text view.
589 defaultFontSizeTextView.setVisibility(View.VISIBLE);
591 // Hide the custom font size edit text.
592 customFontSizeEditText.setVisibility(View.GONE);
594 // 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.
595 customFontSizeEditText.setText(defaultFontSizeString);
596 } else { // A custom font size is selected.
597 // Set the spinner to the custom font size.
598 fontSizeSpinner.setSelection(1);
600 // Hide the default font size text view.
601 defaultFontSizeTextView.setVisibility(View.GONE);
603 // Show the custom font size edit text.
604 customFontSizeEditText.setVisibility(View.GONE);
606 // Set the custom font size.
607 customFontSizeEditText.setText(String.valueOf(fontSizeInt));
610 // Initialize the default font size percentage string.
611 String defaultFontSizePercentageString = defaultFontSizeString + "%";
613 // Set the default font size text in the text view.
614 defaultFontSizeTextView.setText(defaultFontSizePercentageString);
616 // Open the font size spinner when the text view is clicked.
617 defaultFontSizeTextView.setOnClickListener((View v) -> {
618 // Open the user agent spinner.
619 fontSizeSpinner.performClick();
622 // Select the swipe to refresh selection in the spinner.
623 swipeToRefreshSpinner.setSelection(swipeToRefreshInt);
625 // Set the swipe to refresh text.
626 if (defaultSwipeToRefresh)
627 swipeToRefreshTextView.setText(swipeToRefreshArrayAdapter.getItem(DomainsDatabaseHelper.ENABLED));
629 swipeToRefreshTextView.setText(swipeToRefreshArrayAdapter.getItem(DomainsDatabaseHelper.DISABLED));
631 // Set the swipe to refresh icon and text view settings.
632 switch (swipeToRefreshInt) {
633 case DomainsDatabaseHelper.SYSTEM_DEFAULT:
634 // Set the icon color.
635 swipeToRefreshImageView.setSelected(defaultSwipeToRefresh);
637 // Show the swipe to refresh text view.
638 swipeToRefreshTextView.setVisibility(View.VISIBLE);
641 case DomainsDatabaseHelper.ENABLED:
642 // Set the icon color.
643 swipeToRefreshImageView.setSelected(true);
645 // Hide the swipe to refresh text view.
646 swipeToRefreshTextView.setVisibility(View.GONE);
649 case DomainsDatabaseHelper.DISABLED:
650 // Set the icon color.
651 swipeToRefreshImageView.setSelected(false);
653 // Hide the swipe to refresh text view.
654 swipeToRefreshTextView.setVisibility(View.GONE);
658 // Open the swipe to refresh spinner when the text view is clicked.
659 swipeToRefreshTextView.setOnClickListener((View v) -> {
660 // Open the swipe to refresh spinner.
661 swipeToRefreshSpinner.performClick();
664 // Get the WebView theme string arrays.
665 String[] webViewThemeStringArray = resources.getStringArray(R.array.webview_theme_array);
666 String[] webViewThemeEntryValuesStringArray = resources.getStringArray(R.array.webview_theme_entry_values);
668 // Define an app WebView theme entry number.
669 int appWebViewThemeEntryNumber;
671 // 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.
672 if (defaultWebViewTheme.equals(webViewThemeEntryValuesStringArray[1])) { // The light theme is selected.
673 // Store the default WebView theme entry number.
674 appWebViewThemeEntryNumber = 1;
675 } else if (defaultWebViewTheme.equals(webViewThemeEntryValuesStringArray[2])) { // The dark theme is selected.
676 // Store the default WebView theme entry number.
677 appWebViewThemeEntryNumber = 2;
678 } else { // The system default theme is selected.
679 // Store the default WebView theme entry number.
680 appWebViewThemeEntryNumber = 0;
683 // Select the WebView theme in the spinner.
684 webViewThemeSpinner.setSelection(webViewThemeInt);
686 // Set the WebView theme text.
687 if (appWebViewThemeEntryNumber == DomainsDatabaseHelper.SYSTEM_DEFAULT) { // The app WebView theme is system default.
688 // Set the text according to the current UI theme.
689 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) {
690 webViewThemeTextView.setText(webViewThemeStringArray[DomainsDatabaseHelper.LIGHT_THEME]);
692 webViewThemeTextView.setText(webViewThemeStringArray[DomainsDatabaseHelper.DARK_THEME]);
694 } else { // The app WebView theme is not system default.
695 // Set the text according to the app WebView theme.
696 webViewThemeTextView.setText(webViewThemeStringArray[appWebViewThemeEntryNumber]);
699 // Set the WebView theme icon and text visibility.
700 switch (webViewThemeInt) {
701 case DomainsDatabaseHelper.SYSTEM_DEFAULT: // The domain WebView theme is system default.
702 // Set the icon according to the app WebView theme.
703 switch (appWebViewThemeEntryNumber) {
704 case DomainsDatabaseHelper.SYSTEM_DEFAULT: // The default WebView theme is system default.
705 // Set the icon color.
706 webViewThemeImageView.setSelected(currentThemeStatus == Configuration.UI_MODE_NIGHT_NO);
709 case DomainsDatabaseHelper.LIGHT_THEME: // the default WebView theme is light.
710 // Set the icon color.
711 webViewThemeImageView.setSelected(true);
714 case DomainsDatabaseHelper.DARK_THEME: // the default WebView theme is dark.
715 // Set the icon color.
716 webViewThemeImageView.setSelected(false);
720 // Show the WebView theme text view.
721 webViewThemeTextView.setVisibility(View.VISIBLE);
724 case DomainsDatabaseHelper.LIGHT_THEME: // The domain WebView theme is light.
725 // Set the icon color.
726 webViewThemeImageView.setSelected(true);
728 // Hide the WebView theme text view.
729 webViewThemeTextView.setVisibility(View.GONE);
732 case DomainsDatabaseHelper.DARK_THEME: // The domain WebView theme is dark.
733 // Set the icon color.
734 webViewThemeImageView.setSelected(false);
736 // Hide the WebView theme text view.
737 webViewThemeTextView.setVisibility(View.GONE);
741 // Open the WebView theme spinner when the text view is clicked.
742 webViewThemeTextView.setOnClickListener((View v) -> {
743 // Open the WebView theme spinner.
744 webViewThemeSpinner.performClick();
747 // Select the wide viewport in the spinner.
748 wideViewportSpinner.setSelection(wideViewportInt);
750 // Set the default wide viewport text.
751 if (defaultWideViewport)
752 wideViewportTextView.setText(wideViewportArrayAdapter.getItem(DomainsDatabaseHelper.ENABLED));
754 wideViewportTextView.setText(wideViewportArrayAdapter.getItem(DomainsDatabaseHelper.DISABLED));
756 // Set the wide viewport icon and text view settings.
757 switch (wideViewportInt) {
758 case DomainsDatabaseHelper.SYSTEM_DEFAULT:
759 // Set the icon color.
760 wideViewportImageView.setSelected(defaultWideViewport);
762 // Show the wide viewport text view.
763 wideViewportTextView.setVisibility(View.VISIBLE);
766 case DomainsDatabaseHelper.ENABLED:
767 // Set the icon color.
768 wideViewportImageView.setSelected(true);
770 // Hide the wide viewport text view.
771 wideViewportTextView.setVisibility(View.GONE);
774 case DomainsDatabaseHelper.DISABLED:
775 // Set the icon color.
776 wideViewportImageView.setSelected(false);
778 // Hide the wide viewport text view.
779 wideViewportTextView.setVisibility(View.GONE);
783 // Open the wide viewport spinner when the text view is clicked.
784 wideViewportTextView.setOnClickListener((View view) -> {
785 // Open the wide viewport spinner.
786 wideViewportSpinner.performClick();
789 // Display the website images mode in the spinner.
790 displayWebpageImagesSpinner.setSelection(displayImagesInt);
792 // Set the default display images text.
793 if (defaultDisplayWebpageImages) {
794 displayImagesTextView.setText(displayImagesArrayAdapter.getItem(DomainsDatabaseHelper.ENABLED));
796 displayImagesTextView.setText(displayImagesArrayAdapter.getItem(DomainsDatabaseHelper.DISABLED));
799 // Set the display website images icon and text view settings.
800 switch (displayImagesInt) {
801 case DomainsDatabaseHelper.SYSTEM_DEFAULT:
802 // Set the icon color.
803 displayWebpageImagesImageView.setSelected(defaultDisplayWebpageImages);
805 // Show the display images text view.
806 displayImagesTextView.setVisibility(View.VISIBLE);
809 case DomainsDatabaseHelper.ENABLED:
810 // Set the icon color.
811 displayWebpageImagesImageView.setSelected(true);
813 // Hide the display images text view.
814 displayImagesTextView.setVisibility(View.GONE);
817 case DomainsDatabaseHelper.DISABLED:
818 // Set the icon color.
819 displayWebpageImagesImageView.setSelected(false);
821 // Hide the display images text view.
822 displayImagesTextView.setVisibility(View.GONE);
826 // Open the display images spinner when the text view is clicked.
827 displayImagesTextView.setOnClickListener((View view) -> {
828 // Open the user agent spinner.
829 displayWebpageImagesSpinner.performClick();
832 // Set the switch positions.
833 pinnedSslCertificateSwitch.setChecked(pinnedSslCertificateInt == 1);
834 pinnedIpAddressesSwitch.setChecked(pinnedIpAddressesInt == 1);
836 // Set the switch icon colors.
837 pinnedSslCertificateImageView.setSelected(pinnedSslCertificateInt == 1);
838 pinnedIpAddressesImageView.setSelected(pinnedIpAddressesInt == 1);
840 // Store the current date.
841 Date currentDate = Calendar.getInstance().getTime();
843 // Setup the string builders to display the general certificate information in blue. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
844 savedSslIssuedToONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), savedSslIssuedToONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
845 savedSslIssuedToUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), savedSslIssuedToUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
846 savedSslIssuedByCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), savedSslIssuedByCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
847 savedSslIssuedByONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), savedSslIssuedByONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
848 savedSslIssuedByUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), savedSslIssuedByUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
850 // Check the certificate Common Name against the domain name.
851 boolean savedSslCommonNameMatchesDomainName = checkDomainNameAgainstCertificate(domainNameString, savedSslIssuedToCNameString);
853 // Format the issued to Common Name color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
854 if (savedSslCommonNameMatchesDomainName) {
855 savedSslIssuedToCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), savedSslIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
857 savedSslIssuedToCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), savedSslIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
860 // Format the start date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
861 if ((savedSslStartDate != null) && savedSslStartDate.after(currentDate)) { // The certificate start date is in the future.
862 savedSslStartDateStringBuilder.setSpan(redColorSpan, startDateLabel.length(), savedSslStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
863 } else { // The certificate start date is in the past.
864 savedSslStartDateStringBuilder.setSpan(blueColorSpan, startDateLabel.length(), savedSslStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
867 // Format the end date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
868 if ((savedSslEndDate != null) && savedSslEndDate.before(currentDate)) { // The certificate end date is in the past.
869 savedSslEndDateStringBuilder.setSpan(redColorSpan, endDateLabel.length(), savedSslEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
870 } else { // The certificate end date is in the future.
871 savedSslEndDateStringBuilder.setSpan(blueColorSpan, endDateLabel.length(), savedSslEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
874 // Display the saved website SSL certificate strings.
875 savedSslIssuedToCNameTextView.setText(savedSslIssuedToCNameStringBuilder);
876 savedSslIssuedToONameTextView.setText(savedSslIssuedToONameStringBuilder);
877 savedSslIssuedToUNameTextView.setText(savedSslIssuedToUNameStringBuilder);
878 savedSslIssuedByCNameTextView.setText(savedSslIssuedByCNameStringBuilder);
879 savedSslIssuedByONameTextView.setText(savedSslIssuedByONameStringBuilder);
880 savedSslIssuedByUNameTextView.setText(savedSslIssuedByUNameStringBuilder);
881 savedSslStartDateTextView.setText(savedSslStartDateStringBuilder);
882 savedSslEndDateTextView.setText(savedSslEndDateStringBuilder);
884 // Populate the current website SSL certificate if there is one.
885 if (DomainsActivity.sslIssuedToCName != null) {
886 // Get dates from the raw long values.
887 Date currentSslStartDate = new Date(DomainsActivity.sslStartDateLong);
888 Date currentSslEndDate = new Date(DomainsActivity.sslEndDateLong);
890 // Create a spannable string builder for each text view that needs multiple colors of text.
891 SpannableStringBuilder currentSslIssuedToCNameStringBuilder = new SpannableStringBuilder(cNameLabel + DomainsActivity.sslIssuedToCName);
892 SpannableStringBuilder currentSslIssuedToONameStringBuilder = new SpannableStringBuilder(oNameLabel + DomainsActivity.sslIssuedToOName);
893 SpannableStringBuilder currentSslIssuedToUNameStringBuilder = new SpannableStringBuilder(uNameLabel + DomainsActivity.sslIssuedToUName);
894 SpannableStringBuilder currentSslIssuedByCNameStringBuilder = new SpannableStringBuilder(cNameLabel + DomainsActivity.sslIssuedByCName);
895 SpannableStringBuilder currentSslIssuedByONameStringBuilder = new SpannableStringBuilder(oNameLabel + DomainsActivity.sslIssuedByOName);
896 SpannableStringBuilder currentSslIssuedByUNameStringBuilder = new SpannableStringBuilder(uNameLabel + DomainsActivity.sslIssuedByUName);
897 SpannableStringBuilder currentSslStartDateStringBuilder = new SpannableStringBuilder(startDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG)
898 .format(currentSslStartDate));
899 SpannableStringBuilder currentSslEndDateStringBuilder = new SpannableStringBuilder(endDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG)
900 .format(currentSslEndDate));
902 // Setup the string builders to display the general certificate information in blue. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
903 currentSslIssuedToONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), currentSslIssuedToONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
904 currentSslIssuedToUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), currentSslIssuedToUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
905 currentSslIssuedByCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), currentSslIssuedByCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
906 currentSslIssuedByONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), currentSslIssuedByONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
907 currentSslIssuedByUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), currentSslIssuedByUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
909 // Check the certificate Common Name against the domain name.
910 boolean currentSslCommonNameMatchesDomainName = checkDomainNameAgainstCertificate(domainNameString, DomainsActivity.sslIssuedToCName);
912 // Format the issued to Common Name color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
913 if (currentSslCommonNameMatchesDomainName) {
914 currentSslIssuedToCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), currentSslIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
916 currentSslIssuedToCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), currentSslIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
919 // Format the start date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
920 if (currentSslStartDate.after(currentDate)) { // The certificate start date is in the future.
921 currentSslStartDateStringBuilder.setSpan(redColorSpan, startDateLabel.length(), currentSslStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
922 } else { // The certificate start date is in the past.
923 currentSslStartDateStringBuilder.setSpan(blueColorSpan, startDateLabel.length(), currentSslStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
926 // Format the end date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
927 if (currentSslEndDate.before(currentDate)) { // The certificate end date is in the past.
928 currentSslEndDateStringBuilder.setSpan(redColorSpan, endDateLabel.length(), currentSslEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
929 } else { // The certificate end date is in the future.
930 currentSslEndDateStringBuilder.setSpan(blueColorSpan, endDateLabel.length(), currentSslEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
933 // Display the current website SSL certificate strings.
934 currentSslIssuedToCNameTextView.setText(currentSslIssuedToCNameStringBuilder);
935 currentSslIssuedToONameTextView.setText(currentSslIssuedToONameStringBuilder);
936 currentSslIssuedToUNameTextView.setText(currentSslIssuedToUNameStringBuilder);
937 currentSslIssuedByCNameTextView.setText(currentSslIssuedByCNameStringBuilder);
938 currentSslIssuedByONameTextView.setText(currentSslIssuedByONameStringBuilder);
939 currentSslIssuedByUNameTextView.setText(currentSslIssuedByUNameStringBuilder);
940 currentSslStartDateTextView.setText(currentSslStartDateStringBuilder);
941 currentSslEndDateTextView.setText(currentSslEndDateStringBuilder);
944 // Set the initial display status of the SSL certificates card views.
945 if (pinnedSslCertificateSwitch.isChecked()) { // An SSL certificate is pinned.
946 // Set the visibility of the saved SSL certificate.
947 if (savedSslIssuedToCNameString == null) {
948 savedSslCardView.setVisibility(View.GONE);
950 savedSslCardView.setVisibility(View.VISIBLE);
953 // Set the visibility of the current website SSL certificate.
954 if (DomainsActivity.sslIssuedToCName == null) { // There is no current SSL certificate.
955 // Hide the SSL certificate.
956 currentSslCardView.setVisibility(View.GONE);
958 // Show the instruction.
959 noCurrentWebsiteCertificateTextView.setVisibility(View.VISIBLE);
960 } else { // There is a current SSL certificate.
961 // Show the SSL certificate.
962 currentSslCardView.setVisibility(View.VISIBLE);
964 // Hide the instruction.
965 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
968 // Set the status of the radio buttons and the card view backgrounds.
969 if (savedSslCardView.getVisibility() == View.VISIBLE) { // The saved SSL certificate is displayed.
970 // Check the saved SSL certificate radio button.
971 savedSslCertificateRadioButton.setChecked(true);
973 // Uncheck the current website SSL certificate radio button.
974 currentWebsiteCertificateRadioButton.setChecked(false);
976 // Darken the background of the current website SSL certificate linear layout according to the theme.
977 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
978 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
980 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
982 } else if (currentSslCardView.getVisibility() == View.VISIBLE) { // The saved SSL certificate is hidden but the current website SSL certificate is visible.
983 // Check the current website SSL certificate radio button.
984 currentWebsiteCertificateRadioButton.setChecked(true);
986 // Uncheck the saved SSL certificate radio button.
987 savedSslCertificateRadioButton.setChecked(false);
988 } else { // Neither SSL certificate is visible.
989 // Uncheck both radio buttons.
990 savedSslCertificateRadioButton.setChecked(false);
991 currentWebsiteCertificateRadioButton.setChecked(false);
993 } else { // An SSL certificate is not pinned.
994 // Hide the SSl certificates and instructions.
995 savedSslCardView.setVisibility(View.GONE);
996 currentSslCardView.setVisibility(View.GONE);
997 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
999 // Uncheck the radio buttons.
1000 savedSslCertificateRadioButton.setChecked(false);
1001 currentWebsiteCertificateRadioButton.setChecked(false);
1004 // Populate the saved and current IP addresses.
1005 savedIpAddressesTextView.setText(savedIpAddresses);
1006 currentIpAddressesTextView.setText(DomainsActivity.currentIpAddresses);
1008 // Set the initial display status of the IP addresses card views.
1009 if (pinnedIpAddressesSwitch.isChecked()) { // IP addresses are pinned.
1010 // Set the visibility of the saved IP addresses.
1011 if (savedIpAddresses == null) { // There are no saved IP addresses.
1012 savedIpAddressesCardView.setVisibility(View.GONE);
1013 } else { // There are saved IP addresses.
1014 savedIpAddressesCardView.setVisibility(View.VISIBLE);
1017 // Set the visibility of the current IP addresses.
1018 currentIpAddressesCardView.setVisibility(View.VISIBLE);
1020 // Set the status of the radio buttons and the card view backgrounds.
1021 if (savedIpAddressesCardView.getVisibility() == View.VISIBLE) { // The saved IP addresses are displayed.
1022 // Check the saved IP addresses radio button.
1023 savedIpAddressesRadioButton.setChecked(true);
1025 // Uncheck the current IP addresses radio button.
1026 currentIpAddressesRadioButton.setChecked(false);
1028 // Darken the background of the current IP addresses linear layout according to the theme.
1029 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1030 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1032 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1034 } else { // The saved IP addresses are hidden.
1035 // Check the current IP addresses radio button.
1036 currentIpAddressesRadioButton.setChecked(true);
1038 // Uncheck the saved IP addresses radio button.
1039 savedIpAddressesRadioButton.setChecked(false);
1041 } else { // IP addresses are not pinned.
1042 // Hide the IP addresses card views.
1043 savedIpAddressesCardView.setVisibility(View.GONE);
1044 currentIpAddressesCardView.setVisibility(View.GONE);
1046 // Uncheck the radio buttons.
1047 savedIpAddressesRadioButton.setChecked(false);
1048 currentIpAddressesRadioButton.setChecked(false);
1052 // Set the JavaScript switch listener.
1053 javaScriptSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1054 if (isChecked) { // JavaScript is enabled.
1055 // Update the JavaScript icon.
1056 javaScriptImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.javascript_enabled, null));
1058 // Enable the DOM storage `Switch`.
1059 domStorageSwitch.setEnabled(true);
1061 // Update the DOM storage icon.
1062 if (domStorageSwitch.isChecked()) { // DOM storage is enabled.
1063 domStorageImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.dom_storage_enabled, null));
1064 } else { // DOM storage is disabled.
1066 domStorageImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.dom_storage_disabled, null));
1068 } else { // JavaScript is disabled.
1069 // Update the JavaScript icon.
1070 javaScriptImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.privacy_mode, null));
1072 // Disable the DOM storage switch.
1073 domStorageSwitch.setEnabled(false);
1075 // Set the DOM storage icon.
1076 domStorageImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.dom_storage_ghosted, null));
1080 // Set the cookies switch listener.
1081 cookiesSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1082 // Update the cookies icon.
1084 cookiesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.cookies_enabled, null));
1086 cookiesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.cookies_disabled, null));
1090 // Set the DOM Storage switch listener.
1091 domStorageSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1094 domStorageImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.dom_storage_enabled, null));
1097 domStorageImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.dom_storage_disabled, null));
1101 // Set the form data switch listener. It can be removed once the minimum API >= 26.
1102 if (Build.VERSION.SDK_INT < 26) {
1103 formDataSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1106 formDataImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.form_data_enabled, null));
1109 formDataImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.form_data_disabled, null));
1114 // Set the EasyList switch listener.
1115 easyListSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1116 // Update the icon color.
1117 easyListImageView.setSelected(isChecked);
1120 // Set the EasyPrivacy switch listener.
1121 easyPrivacySwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1122 // Update the icon color.
1123 easyPrivacyImageView.setSelected(isChecked);
1126 // Set the Fanboy's Annoyance List switch listener.
1127 fanboysAnnoyanceListSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1128 // Update the icon color.
1129 fanboysAnnoyanceListImageView.setSelected(isChecked);
1132 // Set Fanboy's Social Blocking List switch position.
1133 fanboysSocialBlockingListSwitch.setEnabled(!isChecked);
1135 // Set the Social Blocking List icon ghosted status.
1136 fanboysSocialBlockingListImageView.setEnabled(!isChecked);
1139 // Set the Fanboy's Social Blocking List switch listener.
1140 fanboysSocialBlockingListSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1141 // Update the icon color.
1142 fanboysSocialBlockingListImageView.setSelected(isChecked);
1145 // Set the UltraList switch listener.
1146 ultraListSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1147 // Update the icon color.
1148 ultraListImageView.setSelected(isChecked);
1151 // Set the UltraPrivacy switch listener.
1152 ultraPrivacySwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1153 // Update the icon color.
1154 ultraPrivacyImageView.setSelected(isChecked);
1157 // Set the block all third-party requests switch listener.
1158 blockAllThirdPartyRequestsSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1159 // Update the icon color.
1160 blockAllThirdPartyRequestsImageView.setSelected(isChecked);
1163 // Set the user agent spinner listener.
1164 userAgentSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1166 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1167 // Set the new user agent.
1169 case MainWebViewActivity.DOMAINS_SYSTEM_DEFAULT_USER_AGENT:
1170 // Show the user agent TextView.
1171 userAgentTextView.setVisibility(View.VISIBLE);
1173 // Hide the custom user agent EditText.
1174 customUserAgentEditText.setVisibility(View.GONE);
1176 // Set the user text.
1177 switch (defaultUserAgentArrayPosition) {
1178 case MainWebViewActivity.UNRECOGNIZED_USER_AGENT: // The default user agent name is not on the canonical list.
1179 // This is probably because it was set in an older version of Privacy Browser before the switch to persistent user agent names.
1180 userAgentTextView.setText(defaultUserAgentName);
1183 case MainWebViewActivity.SETTINGS_WEBVIEW_DEFAULT_USER_AGENT:
1184 // Display the `WebView` default user agent.
1185 userAgentTextView.setText(webViewDefaultUserAgentString);
1188 case MainWebViewActivity.SETTINGS_CUSTOM_USER_AGENT:
1189 // Display the custom user agent.
1190 userAgentTextView.setText(defaultCustomUserAgentString);
1194 // Get the user agent string from the user agent data array.
1195 userAgentTextView.setText(userAgentDataArray[defaultUserAgentArrayPosition]);
1199 case MainWebViewActivity.DOMAINS_WEBVIEW_DEFAULT_USER_AGENT:
1200 // Show the user agent TextView and set the text.
1201 userAgentTextView.setVisibility(View.VISIBLE);
1202 userAgentTextView.setText(webViewDefaultUserAgentString);
1204 // Hide the custom user agent EditTex.
1205 customUserAgentEditText.setVisibility(View.GONE);
1208 case MainWebViewActivity.DOMAINS_CUSTOM_USER_AGENT:
1209 // Hide the user agent TextView.
1210 userAgentTextView.setVisibility(View.GONE);
1212 // Show the custom user agent EditText and set the current user agent name as the text.
1213 customUserAgentEditText.setVisibility(View.VISIBLE);
1214 customUserAgentEditText.setText(currentUserAgentName);
1218 // 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.
1219 userAgentTextView.setVisibility(View.VISIBLE);
1220 userAgentTextView.setText(userAgentDataArray[position - 1]);
1222 // Hide `customUserAgentEditText`.
1223 customUserAgentEditText.setVisibility(View.GONE);
1228 public void onNothingSelected(AdapterView<?> parent) {
1233 // Set the X-Requested-With header spinner listener.
1234 xRequestedWithHeaderSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1236 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1237 // Update the icon and the visibility of the text view.
1239 case DomainsDatabaseHelper.SYSTEM_DEFAULT:
1240 // Set the icon color.
1241 xRequestedWithHeaderImageView.setSelected(defaultXRequestedWithHeader);
1243 // Show the X-Requested-With header text view.
1244 xRequestedWithHeaderTextView.setVisibility(View.VISIBLE);
1247 case DomainsDatabaseHelper.ENABLED:
1248 // Set the icon color.
1249 xRequestedWithHeaderImageView.setSelected(true);
1251 // Hide the X-Requested-With header text view.
1252 xRequestedWithHeaderTextView.setVisibility(View.GONE);
1255 case DomainsDatabaseHelper.DISABLED:
1256 // Set the icon color.
1257 xRequestedWithHeaderImageView.setSelected(false);
1259 // Hide the X-Requested-With header text view.
1260 xRequestedWithHeaderTextView.setVisibility(View.GONE);
1266 public void onNothingSelected(AdapterView<?> parent) {
1271 // Set the font size spinner listener.
1272 fontSizeSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1274 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1275 // Update the font size display options.
1276 if (position == 0) { // The system default font size has been selected.
1277 // Show the default font size text view.
1278 defaultFontSizeTextView.setVisibility(View.VISIBLE);
1280 // Hide the custom font size edit text.
1281 customFontSizeEditText.setVisibility(View.GONE);
1282 } else { // A custom font size has been selected.
1283 // Hide the default font size text view.
1284 defaultFontSizeTextView.setVisibility(View.GONE);
1286 // Show the custom font size edit text.
1287 customFontSizeEditText.setVisibility(View.VISIBLE);
1292 public void onNothingSelected(AdapterView<?> parent) {
1297 // Set the swipe to refresh spinner listener.
1298 swipeToRefreshSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1300 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1301 // Update the icon and the visibility of the text view.
1303 case DomainsDatabaseHelper.SYSTEM_DEFAULT:
1304 // Set the icon color.
1305 swipeToRefreshImageView.setSelected(defaultSwipeToRefresh);
1307 // Show the swipe to refresh text view.
1308 swipeToRefreshTextView.setVisibility(View.VISIBLE);
1311 case DomainsDatabaseHelper.ENABLED:
1312 // Set the icon color.
1313 swipeToRefreshImageView.setSelected(true);
1315 // Hide the swipe to refresh text view.
1316 swipeToRefreshTextView.setVisibility(View.GONE);
1319 case DomainsDatabaseHelper.DISABLED:
1320 // Set the icon color.
1321 swipeToRefreshImageView.setSelected(false);
1323 // Hide the swipe to refresh text view.
1324 swipeToRefreshTextView.setVisibility(View.GONE);
1329 public void onNothingSelected(AdapterView<?> parent) {
1334 // Set the WebView theme spinner listener.
1335 webViewThemeSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1337 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1338 // Update the icon and the visibility of the WebView theme text view.
1340 case DomainsDatabaseHelper.SYSTEM_DEFAULT: // the domain WebView theme is system default.
1341 // Set the icon according to the app WebView theme.
1342 switch (appWebViewThemeEntryNumber) {
1343 case DomainsDatabaseHelper.SYSTEM_DEFAULT: // The default WebView theme is system default.
1344 // Set the icon color.
1345 webViewThemeImageView.setSelected(currentThemeStatus == Configuration.UI_MODE_NIGHT_NO);
1348 case DomainsDatabaseHelper.LIGHT_THEME: // The default WebView theme is light.
1349 // Set the icon color.
1350 webViewThemeImageView.setSelected(true);
1353 case DomainsDatabaseHelper.DARK_THEME: // The default WebView theme is dark.
1355 webViewThemeImageView.setSelected(false);
1359 // Show the WebView theme text view.
1360 webViewThemeTextView.setVisibility(View.VISIBLE);
1363 case DomainsDatabaseHelper.LIGHT_THEME: // The domain WebView theme is light.
1364 // Set the icon color.
1365 webViewThemeImageView.setSelected(true);
1367 // Hide the WebView theme text view.
1368 webViewThemeTextView.setVisibility(View.GONE);
1371 case DomainsDatabaseHelper.DARK_THEME: // The domain WebView theme is dark.
1372 // Set the icon color.
1373 webViewThemeImageView.setSelected(false);
1375 // Hide the WebView theme text view.
1376 webViewThemeTextView.setVisibility(View.GONE);
1382 public void onNothingSelected(AdapterView<?> parent) {
1387 // Set the wide viewport spinner listener.
1388 wideViewportSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1390 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1391 // Update the icon and the visibility of the wide viewport text view.
1393 case DomainsDatabaseHelper.SYSTEM_DEFAULT:
1394 // Set the icon color.
1395 wideViewportImageView.setSelected(defaultWideViewport);
1397 // Show the wide viewport text view.
1398 wideViewportTextView.setVisibility(View.VISIBLE);
1401 case DomainsDatabaseHelper.ENABLED:
1402 // Set the icon color.
1403 wideViewportImageView.setSelected(true);
1405 // Hide the wide viewport text view.
1406 wideViewportTextView.setVisibility(View.GONE);
1409 case DomainsDatabaseHelper.DISABLED:
1410 // Set the icon color.
1411 wideViewportImageView.setSelected(false);
1413 // Hid ethe wide viewport text view.
1414 wideViewportTextView.setVisibility(View.GONE);
1420 public void onNothingSelected(AdapterView<?> parent) {
1425 // Set the display webpage images spinner listener.
1426 displayWebpageImagesSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1428 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1429 // Update the icon and the visibility of the display images text view.
1431 case DomainsDatabaseHelper.SYSTEM_DEFAULT:
1432 // Set the icon color.
1433 displayWebpageImagesImageView.setSelected(defaultDisplayWebpageImages);
1435 // Show the display images text view.
1436 displayImagesTextView.setVisibility(View.VISIBLE);
1439 case DomainsDatabaseHelper.ENABLED:
1440 // Set the icon color.
1441 displayWebpageImagesImageView.setSelected(true);
1443 // Hide the display images text view.
1444 displayImagesTextView.setVisibility(View.GONE);
1447 case DomainsDatabaseHelper.DISABLED:
1448 // Set the icon color.
1449 displayWebpageImagesImageView.setSelected(false);
1451 // Hide the display images text view.
1452 displayImagesTextView.setVisibility(View.GONE);
1458 public void onNothingSelected(AdapterView<?> parent) {
1463 // Set the pinned SSL certificate switch listener.
1464 pinnedSslCertificateSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1465 // Update the icon color.
1466 pinnedSslCertificateImageView.setSelected(isChecked);
1468 // Update the views.
1469 if (isChecked) { // SSL certificate pinning is enabled.
1470 // Update the visibility of the saved SSL certificate.
1471 if (savedSslIssuedToCNameString == null) {
1472 savedSslCardView.setVisibility(View.GONE);
1474 savedSslCardView.setVisibility(View.VISIBLE);
1477 // Update the visibility of the current website SSL certificate.
1478 if (DomainsActivity.sslIssuedToCName == null) {
1479 // Hide the SSL certificate.
1480 currentSslCardView.setVisibility(View.GONE);
1482 // Show the instruction.
1483 noCurrentWebsiteCertificateTextView.setVisibility(View.VISIBLE);
1485 // Show the SSL certificate.
1486 currentSslCardView.setVisibility(View.VISIBLE);
1488 // Hide the instruction.
1489 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
1492 // Set the status of the radio buttons.
1493 if (savedSslCardView.getVisibility() == View.VISIBLE) { // The saved SSL certificate is displayed.
1494 // Check the saved SSL certificate radio button.
1495 savedSslCertificateRadioButton.setChecked(true);
1497 // Uncheck the current website SSL certificate radio button.
1498 currentWebsiteCertificateRadioButton.setChecked(false);
1500 // Set the background of the saved SSL certificate linear layout to be transparent.
1501 savedSslCertificateLinearLayout.setBackgroundResource(R.color.transparent);
1503 // Darken the background of the current website SSL certificate linear layout according to the theme.
1504 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1505 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1507 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1510 // Scroll to the current website SSL certificate card.
1511 savedSslCardView.getParent().requestChildFocus(savedSslCardView, savedSslCardView);
1512 } else if (currentSslCardView.getVisibility() == View.VISIBLE) { // The saved SSL certificate is hidden but the current website SSL certificate is visible.
1513 // Check the current website SSL certificate radio button.
1514 currentWebsiteCertificateRadioButton.setChecked(true);
1516 // Uncheck the saved SSL certificate radio button.
1517 savedSslCertificateRadioButton.setChecked(false);
1519 // Set the background of the current website SSL certificate linear layout to be transparent.
1520 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.transparent);
1522 // Darken the background of the saved SSL certificate linear layout according to the theme.
1523 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1524 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1526 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1529 // Scroll to the current website SSL certificate card.
1530 currentSslCardView.getParent().requestChildFocus(currentSslCardView, currentSslCardView);
1531 } else { // Neither SSL certificate is visible.
1532 // Uncheck both radio buttons.
1533 savedSslCertificateRadioButton.setChecked(false);
1534 currentWebsiteCertificateRadioButton.setChecked(false);
1536 // Scroll to the current website SSL certificate card.
1537 noCurrentWebsiteCertificateTextView.getParent().requestChildFocus(noCurrentWebsiteCertificateTextView, noCurrentWebsiteCertificateTextView);
1539 } else { // SSL certificate pinning is disabled.
1540 // Hide the SSl certificates and instructions.
1541 savedSslCardView.setVisibility(View.GONE);
1542 currentSslCardView.setVisibility(View.GONE);
1543 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
1545 // Uncheck the radio buttons.
1546 savedSslCertificateRadioButton.setChecked(false);
1547 currentWebsiteCertificateRadioButton.setChecked(false);
1551 savedSslCardView.setOnClickListener((View view) -> {
1552 // Check the saved SSL certificate radio button.
1553 savedSslCertificateRadioButton.setChecked(true);
1555 // Uncheck the current website SSL certificate radio button.
1556 currentWebsiteCertificateRadioButton.setChecked(false);
1558 // Set the background of the saved SSL certificate linear layout to be transparent.
1559 savedSslCertificateLinearLayout.setBackgroundResource(R.color.transparent);
1561 // Darken the background of the current website SSL certificate linear layout according to the theme.
1562 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1563 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1565 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1569 savedSslCertificateRadioButton.setOnClickListener((View view) -> {
1570 // Check the saved SSL certificate radio button.
1571 savedSslCertificateRadioButton.setChecked(true);
1573 // Uncheck the current website SSL certificate radio button.
1574 currentWebsiteCertificateRadioButton.setChecked(false);
1576 // Set the background of the saved SSL certificate linear layout to be transparent.
1577 savedSslCertificateLinearLayout.setBackgroundResource(R.color.transparent);
1579 // Darken the background of the current website SSL certificate linear layout according to the theme.
1580 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1581 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1583 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1587 currentSslCardView.setOnClickListener((View view) -> {
1588 // Check the current website SSL certificate radio button.
1589 currentWebsiteCertificateRadioButton.setChecked(true);
1591 // Uncheck the saved SSL certificate radio button.
1592 savedSslCertificateRadioButton.setChecked(false);
1594 // Set the background of the current website SSL certificate linear layout to be transparent.
1595 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.transparent);
1597 // Darken the background of the saved SSL certificate linear layout according to the theme.
1598 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1599 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1601 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1605 currentWebsiteCertificateRadioButton.setOnClickListener((View view) -> {
1606 // Check the current website SSL certificate radio button.
1607 currentWebsiteCertificateRadioButton.setChecked(true);
1609 // Uncheck the saved SSL certificate radio button.
1610 savedSslCertificateRadioButton.setChecked(false);
1612 // Set the background of the current website SSL certificate linear layout to be transparent.
1613 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.transparent);
1615 // Darken the background of the saved SSL certificate linear layout according to the theme.
1616 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1617 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1619 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1623 // Set the pinned IP addresses switch listener.
1624 pinnedIpAddressesSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1625 // Update the icon color.
1626 pinnedIpAddressesImageView.setSelected(isChecked);
1628 // Update the views.
1629 if (isChecked) { // IP addresses pinning is enabled.
1630 // Update the visibility of the saved IP addresses card view.
1631 if (savedIpAddresses == null) { // There are no saved IP addresses.
1632 savedIpAddressesCardView.setVisibility(View.GONE);
1633 } else { // There are saved IP addresses.
1634 savedIpAddressesCardView.setVisibility(View.VISIBLE);
1637 // Show the current IP addresses card view.
1638 currentIpAddressesCardView.setVisibility(View.VISIBLE);
1640 // Set the status of the radio buttons.
1641 if (savedIpAddressesCardView.getVisibility() == View.VISIBLE) { // The saved IP addresses are visible.
1642 // Check the saved IP addresses radio button.
1643 savedIpAddressesRadioButton.setChecked(true);
1645 // Uncheck the current IP addresses radio button.
1646 currentIpAddressesRadioButton.setChecked(false);
1648 // Set the background of the saved IP addresses linear layout to be transparent.
1649 savedSslCertificateLinearLayout.setBackgroundResource(R.color.transparent);
1651 // Darken the background of the current IP addresses linear layout according to the theme.
1652 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1653 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1655 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1657 } else { // The saved IP addresses are not visible.
1658 // Check the current IP addresses radio button.
1659 currentIpAddressesRadioButton.setChecked(true);
1661 // Uncheck the saved IP addresses radio button.
1662 savedIpAddressesRadioButton.setChecked(false);
1664 // Set the background of the current IP addresses linear layout to be transparent.
1665 currentIpAddressesLinearLayout.setBackgroundResource(R.color.transparent);
1667 // Darken the background of the saved IP addresses linear layout according to the theme.
1668 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1669 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1671 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1675 // Scroll to the bottom of the card views.
1676 currentIpAddressesCardView.getParent().requestChildFocus(currentIpAddressesCardView, currentIpAddressesCardView);
1677 } else { // IP addresses pinning is disabled.
1678 // Hide the IP addresses card views.
1679 savedIpAddressesCardView.setVisibility(View.GONE);
1680 currentIpAddressesCardView.setVisibility(View.GONE);
1682 // Uncheck the radio buttons.
1683 savedIpAddressesRadioButton.setChecked(false);
1684 currentIpAddressesRadioButton.setChecked(false);
1688 savedIpAddressesCardView.setOnClickListener((View view) -> {
1689 // Check the saved IP addresses radio button.
1690 savedIpAddressesRadioButton.setChecked(true);
1692 // Uncheck the current website IP addresses radio button.
1693 currentIpAddressesRadioButton.setChecked(false);
1695 // Set the background of the saved IP addresses linear layout to be transparent.
1696 savedIpAddressesLinearLayout.setBackgroundResource(R.color.transparent);
1698 // Darken the background of the current IP addresses linear layout according to the theme.
1699 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1700 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1702 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1706 savedIpAddressesRadioButton.setOnClickListener((View view) -> {
1707 // Check the saved IP addresses radio button.
1708 savedIpAddressesRadioButton.setChecked(true);
1710 // Uncheck the current website IP addresses radio button.
1711 currentIpAddressesRadioButton.setChecked(false);
1713 // Set the background of the saved IP addresses linear layout to be transparent.
1714 savedIpAddressesLinearLayout.setBackgroundResource(R.color.transparent);
1716 // Darken the background of the current IP addresses linear layout according to the theme.
1717 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1718 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1720 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1724 currentIpAddressesCardView.setOnClickListener((View view) -> {
1725 // Check the current IP addresses radio button.
1726 currentIpAddressesRadioButton.setChecked(true);
1728 // Uncheck the saved IP addresses radio button.
1729 savedIpAddressesRadioButton.setChecked(false);
1731 // Set the background of the current IP addresses linear layout to be transparent.
1732 currentIpAddressesLinearLayout.setBackgroundResource(R.color.transparent);
1734 // Darken the background of the saved IP addresses linear layout according to the theme.
1735 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1736 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1738 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1742 currentIpAddressesRadioButton.setOnClickListener((View view) -> {
1743 // Check the current IP addresses radio button.
1744 currentIpAddressesRadioButton.setChecked(true);
1746 // Uncheck the saved IP addresses radio button.
1747 savedIpAddressesRadioButton.setChecked(false);
1749 // Set the background of the current IP addresses linear layout to be transparent.
1750 currentIpAddressesLinearLayout.setBackgroundResource(R.color.transparent);
1752 // Darken the background of the saved IP addresses linear layout according to the theme.
1753 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1754 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1756 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1760 // Set the scroll Y.
1761 domainSettingsScrollView.post(() -> domainSettingsScrollView.setScrollY(scrollY));
1763 // Return the domain settings view.
1764 return domainSettingsView;
1767 private boolean checkDomainNameAgainstCertificate(String domainName, String certificateCommonName) {
1768 // Initialize `domainNamesMatch`.
1769 boolean domainNamesMatch = false;
1771 // Check various wildcard permutations if `domainName` and `certificateCommonName` are not empty.
1772 // `noinspection ConstantCondition` removes Android Studio's incorrect lint warning that `domainName` can never be `null`.
1773 if ((domainName != null) && (certificateCommonName != null)) {
1774 // Check if the domains match.
1775 if (domainName.equals(certificateCommonName)) {
1776 domainNamesMatch = true;
1779 // If `domainName` starts with a wildcard, check the base domain against all the subdomains of `certificateCommonName`.
1780 if (!domainNamesMatch && domainName.startsWith("*.") && (domainName.length() > 2)) {
1781 // Remove the initial `*.`.
1782 String baseDomainName = domainName.substring(2);
1784 // Setup a copy of `certificateCommonName` to test subdomains.
1785 String certificateCommonNameSubdomain = certificateCommonName;
1787 // Check all the subdomains in `certificateCommonNameSubdomain` against `baseDomainName`.
1788 while (!domainNamesMatch && certificateCommonNameSubdomain.contains(".")) { // Stop checking if we know that `domainNamesMatch` is `true` or if we run out of `.`.
1789 // Test the `certificateCommonNameSubdomain` against `baseDomainName`.
1790 if (certificateCommonNameSubdomain.equals(baseDomainName)) {
1791 domainNamesMatch = true;
1794 // Strip out the lowest subdomain of `certificateCommonNameSubdomain`.
1796 certificateCommonNameSubdomain = certificateCommonNameSubdomain.substring(certificateCommonNameSubdomain.indexOf(".") + 1);
1797 } catch (IndexOutOfBoundsException e) { // `certificateCommonNameSubdomain` ends with `.`.
1798 certificateCommonNameSubdomain = "";
1803 // If `certificateCommonName` starts with a wildcard, check the base common name against all the subdomains of `domainName`.
1804 if (!domainNamesMatch && certificateCommonName.startsWith("*.") && (certificateCommonName.length() > 2)) {
1805 // Remove the initial `*.`.
1806 String baseCertificateCommonName = certificateCommonName.substring(2);
1808 // Setup a copy of `domainName` to test subdomains.
1809 String domainNameSubdomain = domainName;
1811 // Check all the subdomains in `domainNameSubdomain` against `baseCertificateCommonName`.
1812 while (!domainNamesMatch && domainNameSubdomain.contains(".") && (domainNameSubdomain.length() > 2)) {
1813 // Test the `domainNameSubdomain` against `baseCertificateCommonName`.
1814 if (domainNameSubdomain.equals(baseCertificateCommonName)) {
1815 domainNamesMatch = true;
1818 // Strip out the lowest subdomain of `domainNameSubdomain`.
1820 domainNameSubdomain = domainNameSubdomain.substring(domainNameSubdomain.indexOf(".") + 1);
1821 } catch (IndexOutOfBoundsException e) { // `domainNameSubdomain` ends with `.`.
1822 domainNameSubdomain = "";
1827 // If both names start with a wildcard, check if the root of one contains the root of the other.
1828 if (!domainNamesMatch && domainName.startsWith("*.") && (domainName.length() > 2) && certificateCommonName.startsWith("*.") && (certificateCommonName.length() > 2)) {
1829 // Remove the wildcards.
1830 String rootDomainName = domainName.substring(2);
1831 String rootCertificateCommonName = certificateCommonName.substring(2);
1833 // Check if one name ends with the contents of the other. If so, there will be overlap in the their wildcard subdomains.
1834 if (rootDomainName.endsWith(rootCertificateCommonName) || rootCertificateCommonName.endsWith(rootDomainName)) {
1835 domainNamesMatch = true;
1840 return domainNamesMatch;