2 * Copyright © 2017-2020 Soren Stoutner <soren@stoutner.com>.
4 * This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
6 * Privacy Browser 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 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. If not, see <http://www.gnu.org/licenses/>.
20 package com.stoutner.privacybrowser.fragments;
22 import android.annotation.SuppressLint;
23 import android.content.Context;
24 import android.content.SharedPreferences;
25 import android.content.res.Configuration;
26 import android.content.res.Resources;
27 import android.database.Cursor;
28 import android.os.Build;
29 import android.os.Bundle;
30 import android.preference.PreferenceManager;
31 import android.text.Editable;
32 import android.text.SpannableStringBuilder;
33 import android.text.Spanned;
34 import android.text.TextWatcher;
35 import android.text.style.ForegroundColorSpan;
36 import android.view.LayoutInflater;
37 import android.view.View;
38 import android.view.ViewGroup;
39 import android.webkit.WebView;
40 import android.widget.AdapterView;
41 import android.widget.ArrayAdapter;
42 import android.widget.CompoundButton;
43 import android.widget.EditText;
44 import android.widget.ImageView;
45 import android.widget.LinearLayout;
46 import android.widget.RadioButton;
47 import android.widget.ScrollView;
48 import android.widget.Spinner;
49 import android.widget.TextView;
51 import androidx.annotation.NonNull;
52 import androidx.appcompat.widget.SwitchCompat;
53 import androidx.cardview.widget.CardView;
54 import androidx.core.content.res.ResourcesCompat;
55 import androidx.fragment.app.Fragment; // The AndroidX fragment must be used until minimum API >= 23. Otherwise `getContext()` does not work.
57 import com.stoutner.privacybrowser.R;
58 import com.stoutner.privacybrowser.activities.DomainsActivity;
59 import com.stoutner.privacybrowser.activities.MainWebViewActivity;
60 import com.stoutner.privacybrowser.helpers.DomainsDatabaseHelper;
62 import java.text.DateFormat;
63 import java.util.Calendar;
64 import java.util.Date;
66 public class DomainSettingsFragment extends Fragment {
67 // Initialize the public class constants. These are used by activities calling this fragment.
68 public static final String DATABASE_ID = "database_id";
69 public static final String SCROLL_Y = "scroll_y";
71 // Define the public variables. `databaseId` is public static so it can be accessed from `DomainsActivity`. It is also used in `onCreate()` and `onCreateView()`.
72 public static int databaseId;
74 // Define the class variables.
78 public void onCreate(Bundle savedInstanceState) {
79 // Run the default commands.
80 super.onCreate(savedInstanceState);
82 // Remove the lint warning that `getArguments` might be null.
83 assert getArguments() != null;
85 // Store the database id in `databaseId`.
86 databaseId = getArguments().getInt(DATABASE_ID);
87 scrollY = getArguments().getInt(SCROLL_Y);
90 // The deprecated `getDrawable()` must be used until the minimum API >= 21.
92 public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
93 // Inflate `domain_settings_fragment`. `false` does not attach it to the root `container`.
94 View domainSettingsView = inflater.inflate(R.layout.domain_settings_fragment, container, false);
96 // Get handles for the context and the resources.
97 Context context = getContext();
98 Resources resources = getResources();
100 // Remove the error below that the context might be null.
101 assert context != null;
103 // Get the current theme status.
104 int currentThemeStatus = getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
106 // Get a handle for the shared preference.
107 SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
109 // Store the default settings.
110 String defaultUserAgentName = sharedPreferences.getString("user_agent", getString(R.string.user_agent_default_value));
111 String defaultCustomUserAgentString = sharedPreferences.getString("custom_user_agent", getString(R.string.custom_user_agent_default_value));
112 String defaultFontSizeString = sharedPreferences.getString("font_size", getString(R.string.font_size_default_value));
113 boolean defaultSwipeToRefresh = sharedPreferences.getBoolean("swipe_to_refresh", true);
114 String defaultWebViewTheme = sharedPreferences.getString("webview_theme", getString(R.string.webview_theme_default_value));
115 boolean defaultWideViewport = sharedPreferences.getBoolean("wide_viewport", true);
116 boolean defaultDisplayWebpageImages = sharedPreferences.getBoolean("display_webpage_images", true);
118 // Get handles for the views.
119 ScrollView domainSettingsScrollView = domainSettingsView.findViewById(R.id.domain_settings_scrollview);
120 EditText domainNameEditText = domainSettingsView.findViewById(R.id.domain_settings_name_edittext);
121 ImageView javaScriptImageView = domainSettingsView.findViewById(R.id.javascript_imageview);
122 SwitchCompat javaScriptSwitch = domainSettingsView.findViewById(R.id.javascript_switch);
123 ImageView firstPartyCookiesImageView = domainSettingsView.findViewById(R.id.first_party_cookies_imageview);
124 SwitchCompat firstPartyCookiesSwitch = domainSettingsView.findViewById(R.id.first_party_cookies_switch);
125 LinearLayout thirdPartyCookiesLinearLayout = domainSettingsView.findViewById(R.id.third_party_cookies_linearlayout);
126 ImageView thirdPartyCookiesImageView = domainSettingsView.findViewById(R.id.third_party_cookies_imageview);
127 SwitchCompat thirdPartyCookiesSwitch = domainSettingsView.findViewById(R.id.third_party_cookies_switch);
128 ImageView domStorageImageView = domainSettingsView.findViewById(R.id.dom_storage_imageview);
129 SwitchCompat domStorageSwitch = domainSettingsView.findViewById(R.id.dom_storage_switch);
130 ImageView formDataImageView = domainSettingsView.findViewById(R.id.form_data_imageview); // The form data views can be remove once the minimum API >= 26.
131 SwitchCompat formDataSwitch = domainSettingsView.findViewById(R.id.form_data_switch); // The form data views can be remove once the minimum API >= 26.
132 ImageView easyListImageView = domainSettingsView.findViewById(R.id.easylist_imageview);
133 SwitchCompat easyListSwitch = domainSettingsView.findViewById(R.id.easylist_switch);
134 ImageView easyPrivacyImageView = domainSettingsView.findViewById(R.id.easyprivacy_imageview);
135 SwitchCompat easyPrivacySwitch = domainSettingsView.findViewById(R.id.easyprivacy_switch);
136 ImageView fanboysAnnoyanceListImageView = domainSettingsView.findViewById(R.id.fanboys_annoyance_list_imageview);
137 SwitchCompat fanboysAnnoyanceListSwitch = domainSettingsView.findViewById(R.id.fanboys_annoyance_list_switch);
138 ImageView fanboysSocialBlockingListImageView = domainSettingsView.findViewById(R.id.fanboys_social_blocking_list_imageview);
139 SwitchCompat fanboysSocialBlockingListSwitch = domainSettingsView.findViewById(R.id.fanboys_social_blocking_list_switch);
140 ImageView ultraListImageView = domainSettingsView.findViewById(R.id.ultralist_imageview);
141 SwitchCompat ultraListSwitch = domainSettingsView.findViewById(R.id.ultralist_switch);
142 ImageView ultraPrivacyImageView = domainSettingsView.findViewById(R.id.ultraprivacy_imageview);
143 SwitchCompat ultraPrivacySwitch = domainSettingsView.findViewById(R.id.ultraprivacy_switch);
144 ImageView blockAllThirdPartyRequestsImageView = domainSettingsView.findViewById(R.id.block_all_third_party_requests_imageview);
145 SwitchCompat blockAllThirdPartyRequestsSwitch = domainSettingsView.findViewById(R.id.block_all_third_party_requests_switch);
146 Spinner userAgentSpinner = domainSettingsView.findViewById(R.id.user_agent_spinner);
147 TextView userAgentTextView = domainSettingsView.findViewById(R.id.user_agent_textview);
148 EditText customUserAgentEditText = domainSettingsView.findViewById(R.id.custom_user_agent_edittext);
149 Spinner fontSizeSpinner = domainSettingsView.findViewById(R.id.font_size_spinner);
150 TextView defaultFontSizeTextView = domainSettingsView.findViewById(R.id.default_font_size_textview);
151 EditText customFontSizeEditText = domainSettingsView.findViewById(R.id.custom_font_size_edittext);
152 ImageView swipeToRefreshImageView = domainSettingsView.findViewById(R.id.swipe_to_refresh_imageview);
153 Spinner swipeToRefreshSpinner = domainSettingsView.findViewById(R.id.swipe_to_refresh_spinner);
154 TextView swipeToRefreshTextView = domainSettingsView.findViewById(R.id.swipe_to_refresh_textview);
155 ImageView webViewThemeImageView = domainSettingsView.findViewById(R.id.webview_theme_imageview);
156 Spinner webViewThemeSpinner = domainSettingsView.findViewById(R.id.webview_theme_spinner);
157 TextView webViewThemeTextView = domainSettingsView.findViewById(R.id.webview_theme_textview);
158 ImageView wideViewportImageView = domainSettingsView.findViewById(R.id.wide_viewport_imageview);
159 Spinner wideViewportSpinner = domainSettingsView.findViewById(R.id.wide_viewport_spinner);
160 TextView wideViewportTextView = domainSettingsView.findViewById(R.id.wide_viewport_textview);
161 ImageView displayWebpageImagesImageView = domainSettingsView.findViewById(R.id.display_webpage_images_imageview);
162 Spinner displayWebpageImagesSpinner = domainSettingsView.findViewById(R.id.display_webpage_images_spinner);
163 TextView displayImagesTextView = domainSettingsView.findViewById(R.id.display_webpage_images_textview);
164 ImageView pinnedSslCertificateImageView = domainSettingsView.findViewById(R.id.pinned_ssl_certificate_imageview);
165 SwitchCompat pinnedSslCertificateSwitch = domainSettingsView.findViewById(R.id.pinned_ssl_certificate_switch);
166 CardView savedSslCardView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_cardview);
167 LinearLayout savedSslCertificateLinearLayout = domainSettingsView.findViewById(R.id.saved_ssl_certificate_linearlayout);
168 RadioButton savedSslCertificateRadioButton = domainSettingsView.findViewById(R.id.saved_ssl_certificate_radiobutton);
169 TextView savedSslIssuedToCNameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_to_cname);
170 TextView savedSslIssuedToONameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_to_oname);
171 TextView savedSslIssuedToUNameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_to_uname);
172 TextView savedSslIssuedByCNameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_by_cname);
173 TextView savedSslIssuedByONameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_by_oname);
174 TextView savedSslIssuedByUNameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_by_uname);
175 TextView savedSslStartDateTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_start_date);
176 TextView savedSslEndDateTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_end_date);
177 CardView currentSslCardView = domainSettingsView.findViewById(R.id.current_website_certificate_cardview);
178 LinearLayout currentWebsiteCertificateLinearLayout = domainSettingsView.findViewById(R.id.current_website_certificate_linearlayout);
179 RadioButton currentWebsiteCertificateRadioButton = domainSettingsView.findViewById(R.id.current_website_certificate_radiobutton);
180 TextView currentSslIssuedToCNameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_to_cname);
181 TextView currentSslIssuedToONameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_to_oname);
182 TextView currentSslIssuedToUNameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_to_uname);
183 TextView currentSslIssuedByCNameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_by_cname);
184 TextView currentSslIssuedByONameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_by_oname);
185 TextView currentSslIssuedByUNameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_by_uname);
186 TextView currentSslStartDateTextView = domainSettingsView.findViewById(R.id.current_website_certificate_start_date);
187 TextView currentSslEndDateTextView = domainSettingsView.findViewById(R.id.current_website_certificate_end_date);
188 TextView noCurrentWebsiteCertificateTextView = domainSettingsView.findViewById(R.id.no_current_website_certificate);
189 ImageView pinnedIpAddressesImageView = domainSettingsView.findViewById(R.id.pinned_ip_addresses_imageview);
190 SwitchCompat pinnedIpAddressesSwitch = domainSettingsView.findViewById(R.id.pinned_ip_addresses_switch);
191 CardView savedIpAddressesCardView = domainSettingsView.findViewById(R.id.saved_ip_addresses_cardview);
192 LinearLayout savedIpAddressesLinearLayout = domainSettingsView.findViewById(R.id.saved_ip_addresses_linearlayout);
193 RadioButton savedIpAddressesRadioButton = domainSettingsView.findViewById(R.id.saved_ip_addresses_radiobutton);
194 TextView savedIpAddressesTextView = domainSettingsView.findViewById(R.id.saved_ip_addresses_textview);
195 CardView currentIpAddressesCardView = domainSettingsView.findViewById(R.id.current_ip_addresses_cardview);
196 LinearLayout currentIpAddressesLinearLayout = domainSettingsView.findViewById(R.id.current_ip_addresses_linearlayout);
197 RadioButton currentIpAddressesRadioButton = domainSettingsView.findViewById(R.id.current_ip_addresses_radiobutton);
198 TextView currentIpAddressesTextView = domainSettingsView.findViewById(R.id.current_ip_addresses_textview);
200 // Setup the pinned labels.
201 String cNameLabel = getString(R.string.common_name) + " ";
202 String oNameLabel = getString(R.string.organization) + " ";
203 String uNameLabel = getString(R.string.organizational_unit) + " ";
204 String startDateLabel = getString(R.string.start_date) + " ";
205 String endDateLabel = getString(R.string.end_date) + " ";
207 // Initialize the database handler. The `0` specifies the database version, but that is ignored and set instead using a constant in `DomainsDatabaseHelper`.
208 DomainsDatabaseHelper domainsDatabaseHelper = new DomainsDatabaseHelper(context, null, null, 0);
210 // Get the database cursor for this ID and move it to the first row.
211 Cursor domainCursor = domainsDatabaseHelper.getCursorForId(databaseId);
212 domainCursor.moveToFirst();
214 // Save the cursor entries as variables.
215 String domainNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.DOMAIN_NAME));
216 int javaScriptInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_JAVASCRIPT));
217 int firstPartyCookiesInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FIRST_PARTY_COOKIES));
218 int thirdPartyCookiesInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_THIRD_PARTY_COOKIES));
219 int domStorageInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_DOM_STORAGE));
220 int formDataInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FORM_DATA)); // Form data can be remove once the minimum API >= 26.
221 int easyListInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_EASYLIST));
222 int easyPrivacyInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_EASYPRIVACY));
223 int fanboysAnnoyanceListInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FANBOYS_ANNOYANCE_LIST));
224 int fanboysSocialBlockingListInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FANBOYS_SOCIAL_BLOCKING_LIST));
225 int ultraListInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ULTRALIST));
226 int ultraPrivacyInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_ULTRAPRIVACY));
227 int blockAllThirdPartyRequestsInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.BLOCK_ALL_THIRD_PARTY_REQUESTS));
228 String currentUserAgentName = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.USER_AGENT));
229 int fontSizeInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.FONT_SIZE));
230 int swipeToRefreshInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.SWIPE_TO_REFRESH));
231 int webViewThemeInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.WEBVIEW_THEME));
232 int wideViewportInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.WIDE_VIEWPORT));
233 int displayImagesInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.DISPLAY_IMAGES));
234 int pinnedSslCertificateInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.PINNED_SSL_CERTIFICATE));
235 String savedSslIssuedToCNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_TO_COMMON_NAME));
236 String savedSslIssuedToONameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_TO_ORGANIZATION));
237 String savedSslIssuedToUNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_TO_ORGANIZATIONAL_UNIT));
238 String savedSslIssuedByCNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_BY_COMMON_NAME));
239 String savedSslIssuedByONameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_BY_ORGANIZATION));
240 String savedSslIssuedByUNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_BY_ORGANIZATIONAL_UNIT));
241 int pinnedIpAddressesInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.PINNED_IP_ADDRESSES));
242 String savedIpAddresses = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.IP_ADDRESSES));
244 // Initialize the saved SSL certificate date variables.
245 Date savedSslStartDate = null;
246 Date savedSslEndDate = null;
248 // Only get the saved SSL certificate dates from the cursor if they are not set to `0`.
249 if (domainCursor.getLong(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_START_DATE)) != 0) {
250 savedSslStartDate = new Date(domainCursor.getLong(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_START_DATE)));
253 if (domainCursor.getLong(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_END_DATE)) != 0) {
254 savedSslEndDate = new Date(domainCursor.getLong(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_END_DATE)));
257 // Create array adapters for the spinners.
258 ArrayAdapter<CharSequence> translatedUserAgentArrayAdapter = ArrayAdapter.createFromResource(context, R.array.translated_domain_settings_user_agent_names, R.layout.spinner_item);
259 ArrayAdapter<CharSequence> fontSizeArrayAdapter = ArrayAdapter.createFromResource(context, R.array.font_size_array, R.layout.spinner_item);
260 ArrayAdapter<CharSequence> swipeToRefreshArrayAdapter = ArrayAdapter.createFromResource(context, R.array.swipe_to_refresh_array, R.layout.spinner_item);
261 ArrayAdapter<CharSequence> webViewThemeArrayAdapter = ArrayAdapter.createFromResource(context, R.array.webview_theme_array, R.layout.spinner_item);
262 ArrayAdapter<CharSequence> wideViewportArrayAdapter = ArrayAdapter.createFromResource(context, R.array.wide_viewport_array, R.layout.spinner_item);
263 ArrayAdapter<CharSequence> displayImagesArrayAdapter = ArrayAdapter.createFromResource(context, R.array.display_webpage_images_array, R.layout.spinner_item);
265 // Set the drop down view resource on the spinners.
266 translatedUserAgentArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items);
267 fontSizeArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items);
268 swipeToRefreshArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items);
269 webViewThemeArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items);
270 wideViewportArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items);
271 displayImagesArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items);
273 // Set the array adapters for the spinners.
274 userAgentSpinner.setAdapter(translatedUserAgentArrayAdapter);
275 fontSizeSpinner.setAdapter(fontSizeArrayAdapter);
276 swipeToRefreshSpinner.setAdapter(swipeToRefreshArrayAdapter);
277 webViewThemeSpinner.setAdapter(webViewThemeArrayAdapter);
278 wideViewportSpinner.setAdapter(wideViewportArrayAdapter);
279 displayWebpageImagesSpinner.setAdapter(displayImagesArrayAdapter);
281 // Create a spannable string builder for each TextView that needs multiple colors of text.
282 SpannableStringBuilder savedSslIssuedToCNameStringBuilder = new SpannableStringBuilder(cNameLabel + savedSslIssuedToCNameString);
283 SpannableStringBuilder savedSslIssuedToONameStringBuilder = new SpannableStringBuilder(oNameLabel + savedSslIssuedToONameString);
284 SpannableStringBuilder savedSslIssuedToUNameStringBuilder = new SpannableStringBuilder(uNameLabel + savedSslIssuedToUNameString);
285 SpannableStringBuilder savedSslIssuedByCNameStringBuilder = new SpannableStringBuilder(cNameLabel + savedSslIssuedByCNameString);
286 SpannableStringBuilder savedSslIssuedByONameStringBuilder = new SpannableStringBuilder(oNameLabel + savedSslIssuedByONameString);
287 SpannableStringBuilder savedSslIssuedByUNameStringBuilder = new SpannableStringBuilder(uNameLabel + savedSslIssuedByUNameString);
289 // Initialize the spannable string builders for the saved SSL certificate dates.
290 SpannableStringBuilder savedSslStartDateStringBuilder;
291 SpannableStringBuilder savedSslEndDateStringBuilder;
293 // Leave the SSL certificate dates empty if they are `null`.
294 if (savedSslStartDate == null) {
295 savedSslStartDateStringBuilder = new SpannableStringBuilder(startDateLabel);
297 savedSslStartDateStringBuilder = new SpannableStringBuilder(startDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(savedSslStartDate));
300 if (savedSslEndDate == null) {
301 savedSslEndDateStringBuilder = new SpannableStringBuilder(endDateLabel);
303 savedSslEndDateStringBuilder = new SpannableStringBuilder(endDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(savedSslEndDate));
306 // Create the foreground color spans.
307 final ForegroundColorSpan redColorSpan;
308 final ForegroundColorSpan blueColorSpan;
310 // Set the color spans according to the theme. The deprecated `getColor()` must be used until the minimum API >= 23.
311 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
312 redColorSpan = new ForegroundColorSpan(resources.getColor(R.color.red_900));
313 blueColorSpan = new ForegroundColorSpan(resources.getColor(R.color.violet_500));
315 redColorSpan = new ForegroundColorSpan(resources.getColor(R.color.red_a700));
316 blueColorSpan = new ForegroundColorSpan(resources.getColor(R.color.blue_700));
319 // Set the domain name from the the database cursor.
320 domainNameEditText.setText(domainNameString);
322 // Update the certificates' `Common Name` color when the domain name text changes.
323 domainNameEditText.addTextChangedListener(new TextWatcher() {
325 public void beforeTextChanged(CharSequence s, int start, int count, int after) {
330 public void onTextChanged(CharSequence s, int start, int before, int count) {
335 public void afterTextChanged(Editable s) {
336 // Get the new domain name.
337 String newDomainName = domainNameEditText.getText().toString();
339 // Check the saved SSL certificate against the new domain name.
340 boolean savedSslMatchesNewDomainName = checkDomainNameAgainstCertificate(newDomainName, savedSslIssuedToCNameString);
342 // Create a `SpannableStringBuilder` for the saved certificate `Common Name`.
343 SpannableStringBuilder savedSslCNameStringBuilder = new SpannableStringBuilder(cNameLabel + savedSslIssuedToCNameString);
345 // Format the saved certificate `Common Name` color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
346 if (savedSslMatchesNewDomainName) {
347 savedSslCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), savedSslCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
349 savedSslCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), savedSslCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
352 // Update the saved SSL issued to CName text view.
353 savedSslIssuedToCNameTextView.setText(savedSslCNameStringBuilder);
355 // Update the current website certificate if it exists.
356 if (DomainsActivity.sslIssuedToCName != null) {
357 // Check the current website certificate against the new domain name.
358 boolean currentSslMatchesNewDomainName = checkDomainNameAgainstCertificate(newDomainName, DomainsActivity.sslIssuedToCName);
360 // Create a `SpannableStringBuilder` for the current website certificate `Common Name`.
361 SpannableStringBuilder currentSslCNameStringBuilder = new SpannableStringBuilder(cNameLabel + DomainsActivity.sslIssuedToCName);
363 // Format the current certificate `Common Name` color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
364 if (currentSslMatchesNewDomainName) {
365 currentSslCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), currentSslCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
367 currentSslCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), currentSslCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
370 // Update the current SSL issued to CName text view.
371 currentSslIssuedToCNameTextView.setText(currentSslCNameStringBuilder);
376 // Set the JavaScript switch status.
377 if (javaScriptInt == 1) { // JavaScript is enabled.
378 javaScriptSwitch.setChecked(true);
379 javaScriptImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.javascript_enabled, null));
380 } else { // JavaScript is disabled.
381 javaScriptSwitch.setChecked(false);
382 javaScriptImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.privacy_mode, null));
385 // Set the first-party cookies status. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
386 if (firstPartyCookiesInt == 1) { // First-party cookies are enabled.
387 firstPartyCookiesSwitch.setChecked(true);
388 firstPartyCookiesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.cookies_enabled, null));
389 } else { // First-party cookies are disabled.
390 firstPartyCookiesSwitch.setChecked(false);
392 // Set the icon according to the theme.
393 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
394 firstPartyCookiesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.cookies_disabled_night, null));
396 firstPartyCookiesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.cookies_disabled_day, null));
400 // Only display third-party cookies if SDK_INT >= 21.
401 if (Build.VERSION.SDK_INT >= 21) { // Third-party cookies can be configured for API >= 21.
402 // Only enable third-party-cookies if first-party cookies are enabled.
403 if (firstPartyCookiesInt == 1) { // First-party cookies are enabled.
404 // Set the third-party cookies status. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
405 if (thirdPartyCookiesInt == 1) { // Both first-party and third-party cookies are enabled.
406 // Set the third-party cookies switch to be checked.
407 thirdPartyCookiesSwitch.setChecked(true);
409 // Set the icon to be red.
410 thirdPartyCookiesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.cookies_warning, null));
411 } else { // First party cookies are enabled but third-party cookies are disabled.
412 // Set the third-party cookies switch to be checked.
413 thirdPartyCookiesSwitch.setChecked(false);
415 // Set the icon according to the theme.
416 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
417 thirdPartyCookiesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.cookies_disabled_night, null));
419 thirdPartyCookiesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.cookies_disabled_day, null));
422 } else { // First-party cookies are disabled.
423 // Set the status of third-party cookies.
424 if (thirdPartyCookiesInt == 1) {
425 thirdPartyCookiesSwitch.setChecked(true);
427 thirdPartyCookiesSwitch.setChecked(false);
430 // Disable the third-party cookies switch.
431 thirdPartyCookiesSwitch.setEnabled(false);
433 // Set the icon according to the theme.
434 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
435 thirdPartyCookiesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.cookies_ghosted_night, null));
437 thirdPartyCookiesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.cookies_ghosted_day, null));
440 } else { // Third-party cookies cannot be configured for API <= 21.
441 // Hide the LinearLayout for third-party cookies.
442 thirdPartyCookiesLinearLayout.setVisibility(View.GONE);
445 // Only enable DOM storage if JavaScript is enabled.
446 if (javaScriptInt == 1) { // JavaScript is enabled.
447 // Enable the DOM storage `Switch`.
448 domStorageSwitch.setEnabled(true);
450 // Set the DOM storage status. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
451 if (domStorageInt == 1) { // Both JavaScript and DOM storage are enabled.
452 domStorageSwitch.setChecked(true);
453 domStorageImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.dom_storage_enabled, null));
454 } else { // JavaScript is enabled but DOM storage is disabled.
455 // Set the DOM storage switch to off.
456 domStorageSwitch.setChecked(false);
458 // Set the icon according to the theme.
459 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
460 domStorageImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.dom_storage_disabled_night, null));
462 domStorageImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.dom_storage_disabled_day, null));
465 } else { // JavaScript is disabled.
466 // Disable the DOM storage `Switch`.
467 domStorageSwitch.setEnabled(false);
469 // Set the checked status of DOM storage.
470 if (domStorageInt == 1) { // DOM storage is enabled but JavaScript is disabled.
471 domStorageSwitch.setChecked(true);
472 } else { // Both JavaScript and DOM storage are disabled.
473 domStorageSwitch.setChecked(false);
476 // Set the icon according to the theme.
477 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
478 domStorageImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.dom_storage_ghosted_night, null));
480 domStorageImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.dom_storage_ghosted_day, null));
484 // Set the form data visibility. Form data can be removed once the minimum API >= 26.
485 if (Build.VERSION.SDK_INT >= 26) { // Form data no longer applies to newer versions of Android.
486 // Hide the form data image view and switch.
487 formDataImageView.setVisibility(View.GONE);
488 formDataSwitch.setVisibility(View.GONE);
489 } else { // Form data should be displayed because this is an older version of Android.
490 if (formDataInt == 1) { // Form data is on.
491 // Turn the form data switch on.
492 formDataSwitch.setChecked(true);
494 // Set the form data icon.
495 formDataImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.form_data_enabled, null));
496 } else { // Form data is off.
497 // Turn the form data switch to off.
498 formDataSwitch.setChecked(false);
500 // Set the icon according to the theme. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
501 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
502 formDataImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.form_data_disabled_night, null));
504 formDataImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.form_data_disabled_day, null));
509 // Set the EasyList status. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
510 if (easyListInt == 1) { // EasyList is on.
511 // Turn the switch on.
512 easyListSwitch.setChecked(true);
514 // Set the icon according to the theme.
515 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
516 easyListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_ads_enabled_night, null));
518 easyListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_ads_enabled_day, null));
520 } else { // EasyList is off.
521 // Turn the switch off.
522 easyListSwitch.setChecked(false);
524 // Set the icon according to the theme.
525 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
526 easyListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_ads_disabled_night, null));
528 easyListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_ads_disabled_day, null));
532 // Set the EasyPrivacy status. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
533 if (easyPrivacyInt == 1) { // EasyPrivacy is on.
534 // Turn the switch on.
535 easyPrivacySwitch.setChecked(true);
537 // Set the icon according to the theme.
538 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
539 easyPrivacyImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_tracking_enabled_night, null));
541 easyPrivacyImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_tracking_enabled_day, null));
543 } else { // EasyPrivacy is off.
544 // Turn the switch off.
545 easyPrivacySwitch.setChecked(false);
547 // Set the icon according to the theme.
548 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
549 easyPrivacyImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_tracking_disabled_night, null));
551 easyPrivacyImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_tracking_disabled_day, null));
555 // Set the Fanboy's Annoyance List status. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
556 if (fanboysAnnoyanceListInt == 1) { // Fanboy's Annoyance List is on.
557 // Turn the switch on.
558 fanboysAnnoyanceListSwitch.setChecked(true);
560 // Set the icon according to the theme.
561 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
562 fanboysAnnoyanceListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.social_media_enabled_night, null));
564 fanboysAnnoyanceListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.social_media_enabled_day, null));
566 } else { // Fanboy's Annoyance List is off.
567 // Turn the switch off.
568 fanboysAnnoyanceListSwitch.setChecked(false);
570 // Set the icon according to the theme.
571 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
572 fanboysAnnoyanceListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.social_media_disabled_night, null));
574 fanboysAnnoyanceListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.social_media_disabled_day, null));
578 // Only enable Fanboy's Social Blocking List if Fanboy's Annoyance List is off.
579 if (fanboysAnnoyanceListInt == 0) { // Fanboy's Annoyance List is on.
580 // Enable Fanboy's Social Blocking List switch.
581 fanboysSocialBlockingListSwitch.setEnabled(true);
583 // Enable Fanboy's Social Blocking List. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
584 if (fanboysSocialBlockingListInt == 1) { // Fanboy's Social Blocking List is on.
585 // Turn on Fanboy's Social Blocking List switch.
586 fanboysSocialBlockingListSwitch.setChecked(true);
588 // Set the icon according to the theme.
589 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
590 fanboysSocialBlockingListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.social_media_enabled_night, null));
592 fanboysSocialBlockingListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.social_media_enabled_day, null));
594 } else { // Fanboy's Social Blocking List is off.
595 // Turn off Fanboy's Social Blocking List switch.
596 fanboysSocialBlockingListSwitch.setChecked(false);
598 // Set the icon according to the theme.
599 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
600 fanboysSocialBlockingListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.social_media_disabled_night, null));
602 fanboysSocialBlockingListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.social_media_disabled_day, null));
605 } else { // Fanboy's Annoyance List is on.
606 // Disable Fanboy's Social Blocking List switch.
607 fanboysSocialBlockingListSwitch.setEnabled(false);
609 // Handle the status of Fanboy's Social Blocking List. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
610 if (fanboysSocialBlockingListInt == 1) { // Fanboy's Social Blocking List is on.
611 // Turn on Fanboy's Social Blocking List switch.
612 fanboysSocialBlockingListSwitch.setChecked(true);
613 } else { // Fanboy's Social Blocking List is off.
614 // Turn off Fanboy's Social Blocking List switch.
615 fanboysSocialBlockingListSwitch.setChecked(false);
618 // Set the icon according to the theme.
619 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
620 fanboysSocialBlockingListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.social_media_ghosted_night, null));
622 fanboysSocialBlockingListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.social_media_ghosted_day, null));
626 // Set the UltraList status. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
627 if (ultraListInt == 1) { // UltraList is on.
628 // Turn the switch on.
629 ultraListSwitch.setChecked(true);
631 // Set the icon according to the theme.
632 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
633 ultraListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_ads_enabled_night, null));
635 ultraListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_ads_enabled_day, null));
637 } else { // UltraList is off.
638 // Turn the switch off.
639 ultraListSwitch.setChecked(false);
641 // Set the icon according to the theme.
642 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
643 ultraListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_ads_disabled_night, null));
645 ultraListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_ads_disabled_day, null));
649 // Set the UltraPrivacy status. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
650 if (ultraPrivacyInt == 1) { // UltraPrivacy is on.
651 // Turn the switch on.
652 ultraPrivacySwitch.setChecked(true);
654 // Set the icon according to the theme.
655 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
656 ultraPrivacyImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_tracking_enabled_night, null));
658 ultraPrivacyImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_tracking_enabled_day, null));
660 } else { // EasyPrivacy is off.
661 // Turn the switch off.
662 ultraPrivacySwitch.setChecked(false);
664 // Set the icon according to the theme.
665 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
666 ultraPrivacyImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_tracking_disabled_night, null));
668 ultraPrivacyImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_tracking_disabled_day, null));
672 // Set the third-party resource blocking status. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
673 if (blockAllThirdPartyRequestsInt == 1) { // Blocking all third-party requests is on.
674 // Turn the switch on.
675 blockAllThirdPartyRequestsSwitch.setChecked(true);
677 // Set the icon according to the theme.
678 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
679 blockAllThirdPartyRequestsImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_all_third_party_requests_enabled_night, null));
681 blockAllThirdPartyRequestsImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_all_third_party_requests_enabled_day, null));
683 } else { // Blocking all third-party requests is off.
684 // Turn the switch off.
685 blockAllThirdPartyRequestsSwitch.setChecked(false);
687 // Set the icon according to the theme.
688 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
689 blockAllThirdPartyRequestsImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_all_third_party_requests_disabled_night, null));
691 blockAllThirdPartyRequestsImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_all_third_party_requests_disabled_day, null));
695 // Inflated a WebView to get the default user agent.
696 // `@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.
697 @SuppressLint("InflateParams") View bareWebViewLayout = inflater.inflate(R.layout.bare_webview, null, false);
698 WebView bareWebView = bareWebViewLayout.findViewById(R.id.bare_webview);
699 final String webViewDefaultUserAgentString = bareWebView.getSettings().getUserAgentString();
701 // Get a handle for the user agent array adapter. This array does not contain the `System default` entry.
702 ArrayAdapter<CharSequence> userAgentNamesArray = ArrayAdapter.createFromResource(context, R.array.user_agent_names, R.layout.spinner_item);
704 // Get the positions of the user agent and the default user agent.
705 int userAgentArrayPosition = userAgentNamesArray.getPosition(currentUserAgentName);
706 int defaultUserAgentArrayPosition = userAgentNamesArray.getPosition(defaultUserAgentName);
708 // Get a handle for the user agent data array. This array does not contain the `System default` entry.
709 String[] userAgentDataArray = resources.getStringArray(R.array.user_agent_data);
711 // Set the user agent text.
712 if (currentUserAgentName.equals(getString(R.string.system_default_user_agent))) { // Use the system default user agent.
713 // Set the user agent according to the system default.
714 switch (defaultUserAgentArrayPosition) {
715 case MainWebViewActivity.UNRECOGNIZED_USER_AGENT: // The default user agent name is not on the canonical list.
716 // This is probably because it was set in an older version of Privacy Browser before the switch to persistent user agent names.
717 userAgentTextView.setText(defaultUserAgentName);
720 case MainWebViewActivity.SETTINGS_WEBVIEW_DEFAULT_USER_AGENT:
721 // Display the `WebView` default user agent.
722 userAgentTextView.setText(webViewDefaultUserAgentString);
725 case MainWebViewActivity.SETTINGS_CUSTOM_USER_AGENT:
726 // Display the custom user agent.
727 userAgentTextView.setText(defaultCustomUserAgentString);
731 // Get the user agent string from the user agent data array.
732 userAgentTextView.setText(userAgentDataArray[defaultUserAgentArrayPosition]);
734 } else if (userAgentArrayPosition == MainWebViewActivity.UNRECOGNIZED_USER_AGENT) { // A custom user agent is stored in the current user agent name.
735 // Set the user agent spinner to `Custom user agent`.
736 userAgentSpinner.setSelection(MainWebViewActivity.DOMAINS_CUSTOM_USER_AGENT);
738 // Hide the user agent TextView.
739 userAgentTextView.setVisibility(View.GONE);
741 // Show the custom user agent EditText and set the current user agent name as the text.
742 customUserAgentEditText.setVisibility(View.VISIBLE);
743 customUserAgentEditText.setText(currentUserAgentName);
744 } else { // The user agent name contains one of the canonical user agents.
745 // 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.
746 userAgentSpinner.setSelection(userAgentArrayPosition + 1);
748 // Show the user agent TextView.
749 userAgentTextView.setVisibility(View.VISIBLE);
751 // Hide the custom user agent EditText.
752 customUserAgentEditText.setVisibility(View.GONE);
754 // Set the user agent text.
755 if (userAgentArrayPosition == MainWebViewActivity.DOMAINS_WEBVIEW_DEFAULT_USER_AGENT) { // The WebView default user agent is selected.
756 // Display the WebView default user agent.
757 userAgentTextView.setText(webViewDefaultUserAgentString);
758 } else { // A user agent besides the default is selected.
759 // 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.
760 userAgentTextView.setText(userAgentDataArray[userAgentArrayPosition + 1]);
764 // Open the user agent spinner when the text view is clicked.
765 userAgentTextView.setOnClickListener((View v) -> {
766 // Open the user agent spinner.
767 userAgentSpinner.performClick();
770 // Display the font size settings.
771 if (fontSizeInt == 0) { // `0` is the code for system default font size.
772 // Set the font size to the system default
773 fontSizeSpinner.setSelection(0);
775 // Show the default font size text view.
776 defaultFontSizeTextView.setVisibility(View.VISIBLE);
778 // Hide the custom font size edit text.
779 customFontSizeEditText.setVisibility(View.GONE);
781 // 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.
782 customFontSizeEditText.setText(defaultFontSizeString);
783 } else { // A custom font size is selected.
784 // Set the spinner to the custom font size.
785 fontSizeSpinner.setSelection(1);
787 // Hide the default font size text view.
788 defaultFontSizeTextView.setVisibility(View.GONE);
790 // Show the custom font size edit text.
791 customFontSizeEditText.setVisibility(View.GONE);
793 // Set the custom font size.
794 customFontSizeEditText.setText(String.valueOf(fontSizeInt));
797 // Initialize the default font size percentage string.
798 String defaultFontSizePercentageString = defaultFontSizeString + "%";
800 // Set the default font size text in the text view.
801 defaultFontSizeTextView.setText(defaultFontSizePercentageString);
803 // Open the font size spinner when the text view is clicked.
804 defaultFontSizeTextView.setOnClickListener((View v) -> {
805 // Open the user agent spinner.
806 fontSizeSpinner.performClick();
809 // Select the swipe to refresh selection in the spinner.
810 swipeToRefreshSpinner.setSelection(swipeToRefreshInt);
812 // Set the swipe to refresh text.
813 if (defaultSwipeToRefresh) {
814 swipeToRefreshTextView.setText(swipeToRefreshArrayAdapter.getItem(DomainsDatabaseHelper.ENABLED));
816 swipeToRefreshTextView.setText(swipeToRefreshArrayAdapter.getItem(DomainsDatabaseHelper.DISABLED));
819 // Set the swipe to refresh icon and TextView settings. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
820 switch (swipeToRefreshInt) {
821 case DomainsDatabaseHelper.SYSTEM_DEFAULT:
822 if (defaultSwipeToRefresh) { // Swipe to refresh is enabled by default.
823 // Set the icon according to the theme.
824 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
825 swipeToRefreshImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.refresh_enabled_night, null));
827 swipeToRefreshImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.refresh_enabled_day, null));
829 } else { // Swipe to refresh is disabled by default
830 // Set the icon according to the theme.
831 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
832 swipeToRefreshImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.refresh_disabled_night, null));
834 swipeToRefreshImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.refresh_disabled_day, null));
838 // Show the swipe to refresh TextView.
839 swipeToRefreshTextView.setVisibility(View.VISIBLE);
842 case DomainsDatabaseHelper.ENABLED:
843 // Set the icon according to the theme.
844 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
845 swipeToRefreshImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.refresh_enabled_night, null));
847 swipeToRefreshImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.refresh_enabled_day, null));
850 // Hide the swipe to refresh TextView.`
851 swipeToRefreshTextView.setVisibility(View.GONE);
854 case DomainsDatabaseHelper.DISABLED:
855 // Set the icon according to the theme.
856 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
857 swipeToRefreshImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.refresh_disabled_night, null));
859 swipeToRefreshImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.refresh_disabled_day, null));
862 // Hide the swipe to refresh TextView.
863 swipeToRefreshTextView.setVisibility(View.GONE);
867 // Open the swipe to refresh spinner when the TextView is clicked.
868 swipeToRefreshTextView.setOnClickListener((View v) -> {
869 // Open the swipe to refresh spinner.
870 swipeToRefreshSpinner.performClick();
873 // Get the WebView theme string arrays.
874 String[] webViewThemeStringArray = resources.getStringArray(R.array.webview_theme_array);
875 String[] webViewThemeEntryValuesStringArray = resources.getStringArray(R.array.webview_theme_entry_values);
877 // Define an app WebView theme entry number.
878 int appWebViewThemeEntryNumber;
880 // 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.
881 if (defaultWebViewTheme.equals(webViewThemeEntryValuesStringArray[1])) { // The light theme is selected.
882 // Store the default WebView theme entry number.
883 appWebViewThemeEntryNumber = 1;
884 } else if (defaultWebViewTheme.equals(webViewThemeEntryValuesStringArray[2])) { // The dark theme is selected.
885 // Store the default WebView theme entry number.
886 appWebViewThemeEntryNumber = 2;
887 } else { // The system default theme is selected.
888 // Store the default WebView theme entry number.
889 appWebViewThemeEntryNumber = 0;
892 // Set the WebView theme visibility.
893 if (Build.VERSION.SDK_INT < 21) { // The WebView theme cannot be set on API 19.
894 // Get a handle for the webView theme linear layout.
895 LinearLayout webViewThemeLinearLayout = domainSettingsView.findViewById(R.id.webview_theme_linearlayout);
897 // Hide the WebView theme linear layout.
898 webViewThemeLinearLayout.setVisibility(View.GONE);
899 } else { // The WebView theme can be set on API >= 21.
900 // Select the WebView theme in the spinner.
901 webViewThemeSpinner.setSelection(webViewThemeInt);
903 // Set the WebView theme text.
904 if (appWebViewThemeEntryNumber == DomainsDatabaseHelper.SYSTEM_DEFAULT) { // The app WebView theme is system default.
905 // Set the text according to the current UI theme.
906 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) {
907 webViewThemeTextView.setText(webViewThemeStringArray[DomainsDatabaseHelper.LIGHT_THEME]);
909 webViewThemeTextView.setText(webViewThemeStringArray[DomainsDatabaseHelper.DARK_THEME]);
911 } else { // The app WebView theme is not system default.
912 // Set the text according to the app WebView theme.
913 webViewThemeTextView.setText(webViewThemeStringArray[appWebViewThemeEntryNumber]);
916 // Set the WebView theme icon and text visibility. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
917 switch (webViewThemeInt) {
918 case DomainsDatabaseHelper.SYSTEM_DEFAULT: // The domain WebView theme is system default.
919 // Set the icon according to the app WebView theme.
920 switch (appWebViewThemeEntryNumber) {
921 case DomainsDatabaseHelper.SYSTEM_DEFAULT: // The default WebView theme is system default.
922 // Set the icon according to the app theme.
923 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) {
924 // Set the light mode icon.
925 webViewThemeImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.webview_light_theme_day, null));
927 // Set the dark theme icon.
928 webViewThemeImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.webview_dark_theme_night, null));
932 case DomainsDatabaseHelper.LIGHT_THEME: // the default WebView theme is light.
933 // Set the icon according to the app theme.
934 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) {
935 webViewThemeImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.webview_light_theme_day, null));
937 webViewThemeImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.webview_light_theme_night, null));
941 case DomainsDatabaseHelper.DARK_THEME: // the default WebView theme is dark.
942 // Set the icon according to the app theme.
943 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) {
944 webViewThemeImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.webview_dark_theme_day, null));
946 webViewThemeImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.webview_dark_theme_night, null)); }
950 // Show the WebView theme text view.
951 webViewThemeTextView.setVisibility(View.VISIBLE);
954 case DomainsDatabaseHelper.LIGHT_THEME: // The domain WebView theme is light.
955 // Set the icon according to the app theme.
956 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) {
957 webViewThemeImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.webview_light_theme_day, null));
959 webViewThemeImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.webview_light_theme_night, null));
962 // Hide the WebView theme text view.
963 webViewThemeTextView.setVisibility(View.GONE);
966 case DomainsDatabaseHelper.DARK_THEME: // The domain WebView theme is dark.
967 // Set the icon according to the app theme.
968 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) {
969 webViewThemeImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.webview_dark_theme_day, null));
971 webViewThemeImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.webview_dark_theme_night, null));
974 // Hide the WebView theme text view.
975 webViewThemeTextView.setVisibility(View.GONE);
979 // Open the WebView theme spinner when the text view is clicked.
980 webViewThemeTextView.setOnClickListener((View v) -> {
981 // Open the WebView theme spinner.
982 webViewThemeSpinner.performClick();
986 // Select the wide viewport in the spinner.
987 wideViewportSpinner.setSelection(wideViewportInt);
989 // Set the default wide viewport text.
990 if (defaultWideViewport) {
991 wideViewportTextView.setText(wideViewportArrayAdapter.getItem(DomainsDatabaseHelper.ENABLED));
993 wideViewportTextView.setText(wideViewportArrayAdapter.getItem(DomainsDatabaseHelper.DISABLED));
996 // Set the wide viewport icon and text view settings. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
997 switch (wideViewportInt) {
998 case DomainsDatabaseHelper.SYSTEM_DEFAULT:
999 if (defaultWideViewport) { // Wide viewport enabled by default.
1000 // Set the icon according to the theme.
1001 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1002 wideViewportImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.wide_viewport_enabled_night, null));
1004 wideViewportImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.wide_viewport_enabled_day, null));
1006 } else { // Wide viewport disabled by default.
1007 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1008 wideViewportImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.wide_viewport_disabled_night, null));
1010 wideViewportImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.wide_viewport_disabled_day, null));
1014 // Show the wide viewport text view.
1015 wideViewportTextView.setVisibility(View.VISIBLE);
1018 case DomainsDatabaseHelper.ENABLED:
1019 // Set the icon according to the theme.
1020 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1021 wideViewportImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.wide_viewport_enabled_night, null));
1023 wideViewportImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.wide_viewport_enabled_day, null));
1026 // Hide the wide viewport text view.
1027 wideViewportTextView.setVisibility(View.GONE);
1030 case DomainsDatabaseHelper.DISABLED:
1031 // Set the icon according to the theme.
1032 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1033 wideViewportImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.wide_viewport_disabled_night, null));
1035 wideViewportImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.wide_viewport_disabled_day, null));
1038 // Hide the wide viewport text view.
1039 wideViewportTextView.setVisibility(View.GONE);
1043 // Open the wide viewport spinner when the text view is clicked.
1044 wideViewportTextView.setOnClickListener((View view) -> {
1045 // Open the wide viewport spinner.
1046 wideViewportSpinner.performClick();
1049 // Display the website images mode in the spinner.
1050 displayWebpageImagesSpinner.setSelection(displayImagesInt);
1052 // Set the default display images text.
1053 if (defaultDisplayWebpageImages) {
1054 displayImagesTextView.setText(displayImagesArrayAdapter.getItem(DomainsDatabaseHelper.ENABLED));
1056 displayImagesTextView.setText(displayImagesArrayAdapter.getItem(DomainsDatabaseHelper.DISABLED));
1059 // Set the display website images icon and text view settings. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
1060 switch (displayImagesInt) {
1061 case DomainsDatabaseHelper.SYSTEM_DEFAULT:
1062 if (defaultDisplayWebpageImages) { // Display webpage images enabled by default.
1063 // Set the icon according to the theme.
1064 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1065 displayWebpageImagesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.images_enabled_night, null));
1067 displayWebpageImagesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.images_enabled_day, null));
1069 } else { // Display webpage images disabled by default.
1070 // Set the icon according to the theme.
1071 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1072 displayWebpageImagesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.images_disabled_night, null));
1074 displayWebpageImagesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.images_disabled_day, null));
1078 // Show the display images text view.
1079 displayImagesTextView.setVisibility(View.VISIBLE);
1082 case DomainsDatabaseHelper.ENABLED:
1083 // Set the icon according to the theme.
1084 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1085 displayWebpageImagesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.images_enabled_night, null));
1087 displayWebpageImagesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.images_enabled_day, null));
1090 // Hide the display images text view.
1091 displayImagesTextView.setVisibility(View.GONE);
1094 case DomainsDatabaseHelper.DISABLED:
1095 // Set the icon according to the theme.
1096 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1097 displayWebpageImagesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.images_disabled_night, null));
1099 displayWebpageImagesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.images_disabled_day, null));
1102 // Hide the display images text view.
1103 displayImagesTextView.setVisibility(View.GONE);
1107 // Open the display images spinner when the text view is clicked.
1108 displayImagesTextView.setOnClickListener((View view) -> {
1109 // Open the user agent spinner.
1110 displayWebpageImagesSpinner.performClick();
1113 // Set the pinned SSL certificate icon.
1114 if (pinnedSslCertificateInt == 1) { // Pinned SSL certificate is enabled. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
1115 // Check the switch.
1116 pinnedSslCertificateSwitch.setChecked(true);
1118 // Set the icon according to the theme.
1119 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1120 pinnedSslCertificateImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.ssl_certificate_enabled_night, null));
1122 pinnedSslCertificateImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.ssl_certificate_enabled_day, null));
1124 } else { // Pinned SSL certificate is disabled.
1125 // Uncheck the switch.
1126 pinnedSslCertificateSwitch.setChecked(false);
1128 // Set the icon according to the theme.
1129 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1130 pinnedSslCertificateImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.ssl_certificate_disabled_night, null));
1132 pinnedSslCertificateImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.ssl_certificate_disabled_day, null));
1136 // Store the current date.
1137 Date currentDate = Calendar.getInstance().getTime();
1139 // Setup the string builders to display the general certificate information in blue. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
1140 savedSslIssuedToONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), savedSslIssuedToONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1141 savedSslIssuedToUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), savedSslIssuedToUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1142 savedSslIssuedByCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), savedSslIssuedByCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1143 savedSslIssuedByONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), savedSslIssuedByONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1144 savedSslIssuedByUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), savedSslIssuedByUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1146 // Check the certificate Common Name against the domain name.
1147 boolean savedSslCommonNameMatchesDomainName = checkDomainNameAgainstCertificate(domainNameString, savedSslIssuedToCNameString);
1149 // Format the issued to Common Name color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
1150 if (savedSslCommonNameMatchesDomainName) {
1151 savedSslIssuedToCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), savedSslIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1153 savedSslIssuedToCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), savedSslIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1156 // Format the start date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
1157 if ((savedSslStartDate != null) && savedSslStartDate.after(currentDate)) { // The certificate start date is in the future.
1158 savedSslStartDateStringBuilder.setSpan(redColorSpan, startDateLabel.length(), savedSslStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1159 } else { // The certificate start date is in the past.
1160 savedSslStartDateStringBuilder.setSpan(blueColorSpan, startDateLabel.length(), savedSslStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1163 // Format the end date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
1164 if ((savedSslEndDate != null) && savedSslEndDate.before(currentDate)) { // The certificate end date is in the past.
1165 savedSslEndDateStringBuilder.setSpan(redColorSpan, endDateLabel.length(), savedSslEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1166 } else { // The certificate end date is in the future.
1167 savedSslEndDateStringBuilder.setSpan(blueColorSpan, endDateLabel.length(), savedSslEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1170 // Display the saved website SSL certificate strings.
1171 savedSslIssuedToCNameTextView.setText(savedSslIssuedToCNameStringBuilder);
1172 savedSslIssuedToONameTextView.setText(savedSslIssuedToONameStringBuilder);
1173 savedSslIssuedToUNameTextView.setText(savedSslIssuedToUNameStringBuilder);
1174 savedSslIssuedByCNameTextView.setText(savedSslIssuedByCNameStringBuilder);
1175 savedSslIssuedByONameTextView.setText(savedSslIssuedByONameStringBuilder);
1176 savedSslIssuedByUNameTextView.setText(savedSslIssuedByUNameStringBuilder);
1177 savedSslStartDateTextView.setText(savedSslStartDateStringBuilder);
1178 savedSslEndDateTextView.setText(savedSslEndDateStringBuilder);
1180 // Populate the current website SSL certificate if there is one.
1181 if (DomainsActivity.sslIssuedToCName != null) {
1182 // Get dates from the raw long values.
1183 Date currentSslStartDate = new Date(DomainsActivity.sslStartDateLong);
1184 Date currentSslEndDate = new Date(DomainsActivity.sslEndDateLong);
1186 // Create a spannable string builder for each text view that needs multiple colors of text.
1187 SpannableStringBuilder currentSslIssuedToCNameStringBuilder = new SpannableStringBuilder(cNameLabel + DomainsActivity.sslIssuedToCName);
1188 SpannableStringBuilder currentSslIssuedToONameStringBuilder = new SpannableStringBuilder(oNameLabel + DomainsActivity.sslIssuedToOName);
1189 SpannableStringBuilder currentSslIssuedToUNameStringBuilder = new SpannableStringBuilder(uNameLabel + DomainsActivity.sslIssuedToUName);
1190 SpannableStringBuilder currentSslIssuedByCNameStringBuilder = new SpannableStringBuilder(cNameLabel + DomainsActivity.sslIssuedByCName);
1191 SpannableStringBuilder currentSslIssuedByONameStringBuilder = new SpannableStringBuilder(oNameLabel + DomainsActivity.sslIssuedByOName);
1192 SpannableStringBuilder currentSslIssuedByUNameStringBuilder = new SpannableStringBuilder(uNameLabel + DomainsActivity.sslIssuedByUName);
1193 SpannableStringBuilder currentSslStartDateStringBuilder = new SpannableStringBuilder(startDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG)
1194 .format(currentSslStartDate));
1195 SpannableStringBuilder currentSslEndDateStringBuilder = new SpannableStringBuilder(endDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG)
1196 .format(currentSslEndDate));
1198 // Setup the string builders to display the general certificate information in blue. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
1199 currentSslIssuedToONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), currentSslIssuedToONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1200 currentSslIssuedToUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), currentSslIssuedToUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1201 currentSslIssuedByCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), currentSslIssuedByCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1202 currentSslIssuedByONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), currentSslIssuedByONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1203 currentSslIssuedByUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), currentSslIssuedByUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1205 // Check the certificate Common Name against the domain name.
1206 boolean currentSslCommonNameMatchesDomainName = checkDomainNameAgainstCertificate(domainNameString, DomainsActivity.sslIssuedToCName);
1208 // Format the issued to Common Name color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
1209 if (currentSslCommonNameMatchesDomainName) {
1210 currentSslIssuedToCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), currentSslIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1212 currentSslIssuedToCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), currentSslIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1215 // Format the start date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
1216 if (currentSslStartDate.after(currentDate)) { // The certificate start date is in the future.
1217 currentSslStartDateStringBuilder.setSpan(redColorSpan, startDateLabel.length(), currentSslStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1218 } else { // The certificate start date is in the past.
1219 currentSslStartDateStringBuilder.setSpan(blueColorSpan, startDateLabel.length(), currentSslStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1222 // Format the end date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
1223 if (currentSslEndDate.before(currentDate)) { // The certificate end date is in the past.
1224 currentSslEndDateStringBuilder.setSpan(redColorSpan, endDateLabel.length(), currentSslEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1225 } else { // The certificate end date is in the future.
1226 currentSslEndDateStringBuilder.setSpan(blueColorSpan, endDateLabel.length(), currentSslEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1229 // Display the current website SSL certificate strings.
1230 currentSslIssuedToCNameTextView.setText(currentSslIssuedToCNameStringBuilder);
1231 currentSslIssuedToONameTextView.setText(currentSslIssuedToONameStringBuilder);
1232 currentSslIssuedToUNameTextView.setText(currentSslIssuedToUNameStringBuilder);
1233 currentSslIssuedByCNameTextView.setText(currentSslIssuedByCNameStringBuilder);
1234 currentSslIssuedByONameTextView.setText(currentSslIssuedByONameStringBuilder);
1235 currentSslIssuedByUNameTextView.setText(currentSslIssuedByUNameStringBuilder);
1236 currentSslStartDateTextView.setText(currentSslStartDateStringBuilder);
1237 currentSslEndDateTextView.setText(currentSslEndDateStringBuilder);
1240 // Set the initial display status of the SSL certificates card views.
1241 if (pinnedSslCertificateSwitch.isChecked()) { // An SSL certificate is pinned.
1242 // Set the visibility of the saved SSL certificate.
1243 if (savedSslIssuedToCNameString == null) {
1244 savedSslCardView.setVisibility(View.GONE);
1246 savedSslCardView.setVisibility(View.VISIBLE);
1249 // Set the visibility of the current website SSL certificate.
1250 if (DomainsActivity.sslIssuedToCName == null) { // There is no current SSL certificate.
1251 // Hide the SSL certificate.
1252 currentSslCardView.setVisibility(View.GONE);
1254 // Show the instruction.
1255 noCurrentWebsiteCertificateTextView.setVisibility(View.VISIBLE);
1256 } else { // There is a current SSL certificate.
1257 // Show the SSL certificate.
1258 currentSslCardView.setVisibility(View.VISIBLE);
1260 // Hide the instruction.
1261 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
1264 // Set the status of the radio buttons and the card view backgrounds.
1265 if (savedSslCardView.getVisibility() == View.VISIBLE) { // The saved SSL certificate is displayed.
1266 // Check the saved SSL certificate radio button.
1267 savedSslCertificateRadioButton.setChecked(true);
1269 // Uncheck the current website SSL certificate radio button.
1270 currentWebsiteCertificateRadioButton.setChecked(false);
1272 // Darken the background of the current website SSL certificate linear layout according to the theme.
1273 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1274 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1276 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1278 } else if (currentSslCardView.getVisibility() == View.VISIBLE) { // The saved SSL certificate is hidden but the current website SSL certificate is visible.
1279 // Check the current website SSL certificate radio button.
1280 currentWebsiteCertificateRadioButton.setChecked(true);
1282 // Uncheck the saved SSL certificate radio button.
1283 savedSslCertificateRadioButton.setChecked(false);
1284 } else { // Neither SSL certificate is visible.
1285 // Uncheck both radio buttons.
1286 savedSslCertificateRadioButton.setChecked(false);
1287 currentWebsiteCertificateRadioButton.setChecked(false);
1289 } else { // An SSL certificate is not pinned.
1290 // Hide the SSl certificates and instructions.
1291 savedSslCardView.setVisibility(View.GONE);
1292 currentSslCardView.setVisibility(View.GONE);
1293 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
1295 // Uncheck the radio buttons.
1296 savedSslCertificateRadioButton.setChecked(false);
1297 currentWebsiteCertificateRadioButton.setChecked(false);
1300 // Set the pinned IP addresses icon.
1301 if (pinnedIpAddressesInt == 1) { // Pinned IP addresses is enabled. Once the minimum API >= 21 a selector can be sued as the tint mode instead of specifying different icons.
1302 // Check the switch.
1303 pinnedIpAddressesSwitch.setChecked(true);
1305 // Set the icon according to the theme.
1306 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1307 pinnedIpAddressesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.ssl_certificate_enabled_night, null));
1309 pinnedIpAddressesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.ssl_certificate_enabled_day, null));
1311 } else { // Pinned IP Addresses is disabled.
1312 // Uncheck the switch.
1313 pinnedIpAddressesSwitch.setChecked(false);
1315 // Set the icon according to the theme.
1316 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1317 pinnedIpAddressesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.ssl_certificate_disabled_night, null));
1319 pinnedIpAddressesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.ssl_certificate_disabled_day, null));
1323 // Populate the saved and current IP addresses.
1324 savedIpAddressesTextView.setText(savedIpAddresses);
1325 currentIpAddressesTextView.setText(DomainsActivity.currentIpAddresses);
1327 // Set the initial display status of the IP addresses card views.
1328 if (pinnedIpAddressesSwitch.isChecked()) { // IP addresses are pinned.
1329 // Set the visibility of the saved IP addresses.
1330 if (savedIpAddresses == null) { // There are no saved IP addresses.
1331 savedIpAddressesCardView.setVisibility(View.GONE);
1332 } else { // There are saved IP addresses.
1333 savedIpAddressesCardView.setVisibility(View.VISIBLE);
1336 // Set the visibility of the current IP addresses.
1337 currentIpAddressesCardView.setVisibility(View.VISIBLE);
1339 // Set the status of the radio buttons and the card view backgrounds.
1340 if (savedIpAddressesCardView.getVisibility() == View.VISIBLE) { // The saved IP addresses are displayed.
1341 // Check the saved IP addresses radio button.
1342 savedIpAddressesRadioButton.setChecked(true);
1344 // Uncheck the current IP addresses radio button.
1345 currentIpAddressesRadioButton.setChecked(false);
1347 // Darken the background of the current IP addresses linear layout according to the theme.
1348 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1349 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1351 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1353 } else { // The saved IP addresses are hidden.
1354 // Check the current IP addresses radio button.
1355 currentIpAddressesRadioButton.setChecked(true);
1357 // Uncheck the saved IP addresses radio button.
1358 savedIpAddressesRadioButton.setChecked(false);
1360 } else { // IP addresses are not pinned.
1361 // Hide the IP addresses card views.
1362 savedIpAddressesCardView.setVisibility(View.GONE);
1363 currentIpAddressesCardView.setVisibility(View.GONE);
1365 // Uncheck the radio buttons.
1366 savedIpAddressesRadioButton.setChecked(false);
1367 currentIpAddressesRadioButton.setChecked(false);
1371 // Set the JavaScript switch listener.
1372 javaScriptSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1373 if (isChecked) { // JavaScript is enabled.
1374 // Update the JavaScript icon.
1375 javaScriptImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.javascript_enabled, null));
1377 // Enable the DOM storage `Switch`.
1378 domStorageSwitch.setEnabled(true);
1380 // Update the DOM storage icon.
1381 if (domStorageSwitch.isChecked()) { // DOM storage is enabled.
1382 domStorageImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.dom_storage_enabled, null));
1383 } else { // DOM storage is disabled.
1384 // Set the icon according to the theme.
1385 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1386 domStorageImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.dom_storage_disabled_night, null));
1388 domStorageImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.dom_storage_disabled_day, null));
1391 } else { // JavaScript is disabled.
1392 // Update the JavaScript icon.
1393 javaScriptImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.privacy_mode, null));
1395 // Disable the DOM storage `Switch`.
1396 domStorageSwitch.setEnabled(false);
1398 // Set the DOM storage icon according to the theme.
1399 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1400 domStorageImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.dom_storage_ghosted_night, null));
1402 domStorageImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.dom_storage_ghosted_day, null));
1407 // Set the first-party cookies switch listener.
1408 firstPartyCookiesSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1409 if (isChecked) { // First-party cookies are enabled.
1410 // Update the first-party cookies icon.
1411 firstPartyCookiesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.cookies_enabled, null));
1413 // Enable the third-party cookies switch.
1414 thirdPartyCookiesSwitch.setEnabled(true);
1416 // Update the third-party cookies icon.
1417 if (thirdPartyCookiesSwitch.isChecked()) { // Third-party cookies are enabled.
1418 // Set the third-party cookies icon to be red.
1419 thirdPartyCookiesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.cookies_warning, null));
1420 } else { // Third-party cookies are disabled.
1421 // Set the third-party cookies icon according to the theme.
1422 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1423 thirdPartyCookiesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.cookies_disabled_night, null));
1425 thirdPartyCookiesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.cookies_disabled_day, null));
1428 } else { // First-party cookies are disabled.
1429 // Update the first-party cookies icon according to the theme.
1430 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1431 firstPartyCookiesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.cookies_disabled_night, null));
1433 firstPartyCookiesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.cookies_disabled_day, null));
1436 // Disable the third-party cookies switch.
1437 thirdPartyCookiesSwitch.setEnabled(false);
1439 // Set the third-party cookies icon according to the theme.
1440 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1441 thirdPartyCookiesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.cookies_ghosted_night, null));
1443 thirdPartyCookiesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.cookies_ghosted_day, null));
1448 // Set the third-party cookies switch listener.
1449 thirdPartyCookiesSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1452 // Set the third-party cookies icon to be red.
1453 thirdPartyCookiesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.cookies_warning, null));
1455 // Update the third-party cookies icon according to the theme.
1456 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1457 thirdPartyCookiesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.cookies_disabled_night, null));
1459 thirdPartyCookiesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.cookies_disabled_day, null));
1464 // Set the DOM Storage switch listener.
1465 domStorageSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1468 domStorageImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.dom_storage_enabled, null));
1470 // Set the icon according to the theme.
1471 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1472 domStorageImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.dom_storage_disabled_night, null));
1474 domStorageImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.dom_storage_disabled_day, null));
1479 // Set the form data switch listener. It can be removed once the minimum API >= 26.
1480 if (Build.VERSION.SDK_INT < 26) {
1481 formDataSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1484 formDataImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.form_data_enabled, null));
1486 // Set the icon according to the theme.
1487 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1488 formDataImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.form_data_disabled_night, null));
1490 formDataImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.form_data_disabled_day, null));
1496 // Set the EasyList switch listener.
1497 easyListSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1499 if (isChecked) { // EasyList is on.
1500 // Set the icon according to the theme.
1501 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1502 easyListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_ads_enabled_night, null));
1504 easyListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_ads_enabled_day, null));
1506 } else { // EasyList is off.
1507 // Set the icon according to the theme.
1508 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1509 easyListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_ads_disabled_night, null));
1511 easyListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_ads_disabled_day, null));
1516 // Set the EasyPrivacy switch listener.
1517 easyPrivacySwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1519 if (isChecked) { // EasyPrivacy is on.
1520 // Set the icon according to the theme.
1521 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1522 easyPrivacyImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_tracking_enabled_night, null));
1524 easyPrivacyImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_tracking_enabled_day, null));
1526 } else { // EasyPrivacy is off.
1527 // Set the icon according to the theme.
1528 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1529 easyPrivacyImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_tracking_disabled_night, null));
1531 easyPrivacyImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_tracking_disabled_day, null));
1536 // Set the Fanboy's Annoyance List switch listener.
1537 fanboysAnnoyanceListSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1538 // Update the icon and Fanboy's Social Blocking List.
1539 if (isChecked) { // Fanboy's Annoyance List is on.
1540 // Set the icon according to the theme.
1541 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1542 fanboysAnnoyanceListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.social_media_enabled_night, null));
1544 fanboysAnnoyanceListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.social_media_enabled_day, null));
1547 // Disable the Fanboy's Social Blocking List switch.
1548 fanboysSocialBlockingListSwitch.setEnabled(false);
1550 // Update the Fanboy's Social Blocking List icon according to the theme.
1551 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1552 fanboysSocialBlockingListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.social_media_ghosted_night, null));
1554 fanboysSocialBlockingListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.social_media_ghosted_day, null));
1556 } else { // Fanboy's Annoyance List is off.
1557 // Set the icon according to the theme.
1558 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1559 fanboysAnnoyanceListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.social_media_disabled_night, null));
1561 fanboysAnnoyanceListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.social_media_disabled_day, null));
1564 // Enable the Fanboy's Social Blocking List switch.
1565 fanboysSocialBlockingListSwitch.setEnabled(true);
1567 // Update the Fanboy's Social Blocking List icon.
1568 if (fanboysSocialBlockingListSwitch.isChecked()) { // Fanboy's Social Blocking List is on.
1569 // Update the icon according to the theme.
1570 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1571 fanboysSocialBlockingListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.social_media_enabled_night, null));
1573 fanboysSocialBlockingListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.social_media_enabled_day, null));
1575 } else { // Fanboy's Social Blocking List is off.
1576 // Update the icon according to the theme.
1577 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1578 fanboysSocialBlockingListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.social_media_disabled_night, null));
1580 fanboysSocialBlockingListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.social_media_disabled_day, null));
1587 // Set the Fanboy's Social Blocking List switch listener.
1588 fanboysSocialBlockingListSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1590 if (isChecked) { // Fanboy's Social Blocking List is on.
1591 // Set the icon according to the theme.
1592 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1593 fanboysSocialBlockingListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.social_media_enabled_night, null));
1595 fanboysSocialBlockingListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.social_media_enabled_day, null));
1597 } else { // Fanboy's Social Blocking List is off.
1598 // Set the icon according to the theme.
1599 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1600 fanboysSocialBlockingListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.social_media_disabled_night, null));
1602 fanboysSocialBlockingListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.social_media_disabled_day, null));
1607 // Set the UltraList switch listener.
1608 ultraListSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1610 if (isChecked) { // UltraList is on.
1611 // Set the icon according to the theme.
1612 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1613 ultraListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_ads_enabled_night, null));
1615 ultraListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_ads_enabled_day, null));
1617 } else { // UltraList is off.
1618 // Set the icon according to the theme.
1619 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1620 ultraListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_ads_disabled_night, null));
1622 ultraListImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_ads_disabled_day, null));
1627 // Set the UltraPrivacy switch listener.
1628 ultraPrivacySwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1630 if (isChecked) { // UltraPrivacy is on.
1631 // Set the icon according to the theme.
1632 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1633 ultraPrivacyImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_tracking_enabled_night, null));
1635 ultraPrivacyImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_tracking_enabled_day, null));
1637 } else { // UltraPrivacy is off.
1638 // Set the icon according to the theme.
1639 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1640 ultraPrivacyImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_tracking_disabled_night, null));
1642 ultraPrivacyImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_tracking_disabled_day, null));
1647 // Set the block all third-party requests switch listener.
1648 blockAllThirdPartyRequestsSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1650 if (isChecked) { // Blocking all third-party requests is on.
1651 // Set the icon according to the theme.
1652 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1653 blockAllThirdPartyRequestsImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_all_third_party_requests_enabled_night, null));
1655 blockAllThirdPartyRequestsImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_all_third_party_requests_enabled_day, null));
1657 } else { // Blocking all third-party requests is off.
1658 // Set the icon according to the theme.
1659 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1660 blockAllThirdPartyRequestsImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_all_third_party_requests_disabled_night, null));
1662 blockAllThirdPartyRequestsImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.block_all_third_party_requests_disabled_day, null));
1667 // Set the user agent spinner listener.
1668 userAgentSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1670 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1671 // Set the new user agent.
1673 case MainWebViewActivity.DOMAINS_SYSTEM_DEFAULT_USER_AGENT:
1674 // Show the user agent TextView.
1675 userAgentTextView.setVisibility(View.VISIBLE);
1677 // Hide the custom user agent EditText.
1678 customUserAgentEditText.setVisibility(View.GONE);
1680 // Set the user text.
1681 switch (defaultUserAgentArrayPosition) {
1682 case MainWebViewActivity.UNRECOGNIZED_USER_AGENT: // The default user agent name is not on the canonical list.
1683 // This is probably because it was set in an older version of Privacy Browser before the switch to persistent user agent names.
1684 userAgentTextView.setText(defaultUserAgentName);
1687 case MainWebViewActivity.SETTINGS_WEBVIEW_DEFAULT_USER_AGENT:
1688 // Display the `WebView` default user agent.
1689 userAgentTextView.setText(webViewDefaultUserAgentString);
1692 case MainWebViewActivity.SETTINGS_CUSTOM_USER_AGENT:
1693 // Display the custom user agent.
1694 userAgentTextView.setText(defaultCustomUserAgentString);
1698 // Get the user agent string from the user agent data array.
1699 userAgentTextView.setText(userAgentDataArray[defaultUserAgentArrayPosition]);
1703 case MainWebViewActivity.DOMAINS_WEBVIEW_DEFAULT_USER_AGENT:
1704 // Show the user agent TextView and set the text.
1705 userAgentTextView.setVisibility(View.VISIBLE);
1706 userAgentTextView.setText(webViewDefaultUserAgentString);
1708 // Hide the custom user agent EditTex.
1709 customUserAgentEditText.setVisibility(View.GONE);
1712 case MainWebViewActivity.DOMAINS_CUSTOM_USER_AGENT:
1713 // Hide the user agent TextView.
1714 userAgentTextView.setVisibility(View.GONE);
1716 // Show the custom user agent EditText and set the current user agent name as the text.
1717 customUserAgentEditText.setVisibility(View.VISIBLE);
1718 customUserAgentEditText.setText(currentUserAgentName);
1722 // 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.
1723 userAgentTextView.setVisibility(View.VISIBLE);
1724 userAgentTextView.setText(userAgentDataArray[position - 1]);
1726 // Hide `customUserAgentEditText`.
1727 customUserAgentEditText.setVisibility(View.GONE);
1732 public void onNothingSelected(AdapterView<?> parent) {
1737 // Set the font size spinner listener.
1738 fontSizeSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1740 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1741 // Update the font size display options.
1742 if (position == 0) { // The system default font size has been selected.
1743 // Show the default font size text view.
1744 defaultFontSizeTextView.setVisibility(View.VISIBLE);
1746 // Hide the custom font size edit text.
1747 customFontSizeEditText.setVisibility(View.GONE);
1748 } else { // A custom font size has been selected.
1749 // Hide the default font size text view.
1750 defaultFontSizeTextView.setVisibility(View.GONE);
1752 // Show the custom font size edit text.
1753 customFontSizeEditText.setVisibility(View.VISIBLE);
1758 public void onNothingSelected(AdapterView<?> parent) {
1763 // Set the swipe to refresh spinner listener.
1764 swipeToRefreshSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1766 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1767 // Update the icon and the visibility of `nightModeTextView`. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
1769 case DomainsDatabaseHelper.SYSTEM_DEFAULT:
1770 if (defaultSwipeToRefresh) { // Swipe to refresh enabled by default.
1771 // Set the icon according to the theme.
1772 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1773 swipeToRefreshImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.refresh_enabled_night, null));
1775 swipeToRefreshImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.refresh_enabled_day, null));
1777 } else { // Swipe to refresh disabled by default.
1778 // Set the icon according to the theme.
1779 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1780 swipeToRefreshImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.refresh_disabled_night, null));
1782 swipeToRefreshImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.refresh_disabled_day, null));
1786 // Show the swipe to refresh TextView.
1787 swipeToRefreshTextView.setVisibility(View.VISIBLE);
1790 case DomainsDatabaseHelper.ENABLED:
1791 // Set the icon according to the theme.
1792 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1793 swipeToRefreshImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.refresh_enabled_night, null));
1795 swipeToRefreshImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.refresh_enabled_day, null));
1798 // Hide the swipe to refresh TextView.
1799 swipeToRefreshTextView.setVisibility(View.GONE);
1802 case DomainsDatabaseHelper.DISABLED:
1803 // Set the icon according to the theme.
1804 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1805 swipeToRefreshImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.refresh_disabled_night, null));
1807 swipeToRefreshImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.refresh_disabled_day, null));
1810 // Hide the swipe to refresh TextView.
1811 swipeToRefreshTextView.setVisibility(View.GONE);
1816 public void onNothingSelected(AdapterView<?> parent) {
1821 // Set the WebView theme spinner listener.
1822 webViewThemeSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1824 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1825 // Update the icon and the visibility of the WebView theme text view. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
1827 case DomainsDatabaseHelper.SYSTEM_DEFAULT: // the domain WebView theme is system default.
1828 // Set the icon according to the app WebView theme.
1829 switch (appWebViewThemeEntryNumber) {
1830 case DomainsDatabaseHelper.SYSTEM_DEFAULT: // The default WebView theme is system default.
1831 // Set the icon according to the app theme.
1832 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) {
1833 // Set the light mode icon.
1834 webViewThemeImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.webview_light_theme_day, null));
1836 // Set the dark theme icon.
1837 webViewThemeImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.webview_dark_theme_night, null));
1841 case DomainsDatabaseHelper.LIGHT_THEME: // The default WebView theme is light.
1842 // Set the icon according to the app theme.
1843 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) {
1844 webViewThemeImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.webview_light_theme_day, null));
1846 webViewThemeImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.webview_light_theme_night, null));
1850 case DomainsDatabaseHelper.DARK_THEME: // The default WebView theme is dark.
1851 // Set the icon according to the app theme.
1852 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) {
1853 webViewThemeImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.webview_dark_theme_day, null));
1855 webViewThemeImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.webview_dark_theme_night, null));
1860 // Show the WebView theme text view.
1861 webViewThemeTextView.setVisibility(View.VISIBLE);
1864 case DomainsDatabaseHelper.LIGHT_THEME: // The domain WebView theme is light.
1865 // Set the icon according to the app theme.
1866 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) {
1867 webViewThemeImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.webview_light_theme_day, null));
1869 webViewThemeImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.webview_light_theme_night, null));
1872 // Hide the WebView theme text view.
1873 webViewThemeTextView.setVisibility(View.GONE);
1876 case DomainsDatabaseHelper.DARK_THEME: // The domain WebView theme is dark.
1877 // Set the icon according to the app theme.
1878 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) {
1879 webViewThemeImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.webview_dark_theme_day, null));
1881 webViewThemeImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.webview_dark_theme_night, null));
1884 // Hide the WebView theme text view.
1885 webViewThemeTextView.setVisibility(View.GONE);
1891 public void onNothingSelected(AdapterView<?> parent) {
1896 // Set the wide viewport spinner listener.
1897 wideViewportSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1899 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1900 // Update the icon and the visibility of the wide viewport text view.
1902 case DomainsDatabaseHelper.SYSTEM_DEFAULT:
1903 if (defaultWideViewport) { // Wide viewport is enabled by default.
1904 // Set the icon according to the theme.
1905 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1906 wideViewportImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.wide_viewport_enabled_night, null));
1908 wideViewportImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.wide_viewport_enabled_day, null));
1910 } else { // Wide viewport is disabled by default.
1911 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1912 wideViewportImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.wide_viewport_disabled_night, null));
1914 wideViewportImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.wide_viewport_disabled_day, null));
1918 // Show the wide viewport text view.
1919 wideViewportTextView.setVisibility(View.VISIBLE);
1922 case DomainsDatabaseHelper.ENABLED:
1923 // Set the icon according to the theme.
1924 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1925 wideViewportImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.wide_viewport_enabled_night, null));
1927 wideViewportImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.wide_viewport_enabled_day, null));
1930 // Hide the wide viewport text view.
1931 wideViewportTextView.setVisibility(View.GONE);
1934 case DomainsDatabaseHelper.DISABLED:
1935 // Set the icon according to the theme.
1936 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1937 wideViewportImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.wide_viewport_disabled_night, null));
1939 wideViewportImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.wide_viewport_disabled_day, null));
1942 // Hid ethe wide viewport text view.
1943 wideViewportTextView.setVisibility(View.GONE);
1949 public void onNothingSelected(AdapterView<?> parent) {
1954 // Set the display webpage images spinner listener.
1955 displayWebpageImagesSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1957 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1958 // Update the icon and the visibility of the display images text view.
1960 case DomainsDatabaseHelper.SYSTEM_DEFAULT:
1961 if (defaultDisplayWebpageImages) { // Display webpage images is enabled by default.
1962 // Set the icon according to the theme.
1963 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1964 displayWebpageImagesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.images_enabled_night, null));
1966 displayWebpageImagesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.images_enabled_day, null));
1968 } else { // Display webpage images is disabled by default.
1969 // Set the icon according to the theme.
1970 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1971 displayWebpageImagesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.images_disabled_night, null));
1973 displayWebpageImagesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.images_disabled_day, null));
1977 // Show the display images text view.
1978 displayImagesTextView.setVisibility(View.VISIBLE);
1981 case DomainsDatabaseHelper.ENABLED:
1982 // Set the icon according to the theme.
1983 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1984 displayWebpageImagesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.images_enabled_night, null));
1986 displayWebpageImagesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.images_enabled_day, null));
1989 // Hide the display images text view.
1990 displayImagesTextView.setVisibility(View.GONE);
1993 case DomainsDatabaseHelper.DISABLED:
1994 // Set the icon according to the theme.
1995 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
1996 displayWebpageImagesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.images_disabled_night, null));
1998 displayWebpageImagesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.images_disabled_day, null));
2001 // Hide the display images text view.
2002 displayImagesTextView.setVisibility(View.GONE);
2008 public void onNothingSelected(AdapterView<?> parent) {
2013 // Set the pinned SSL certificate switch listener.
2014 pinnedSslCertificateSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
2016 if (isChecked) { // SSL certificate pinning is enabled.
2017 // Set the icon according to the theme.
2018 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
2019 pinnedSslCertificateImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.ssl_certificate_enabled_night, null));
2021 pinnedSslCertificateImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.ssl_certificate_enabled_day, null));
2024 // Update the visibility of the saved SSL certificate.
2025 if (savedSslIssuedToCNameString == null) {
2026 savedSslCardView.setVisibility(View.GONE);
2028 savedSslCardView.setVisibility(View.VISIBLE);
2031 // Update the visibility of the current website SSL certificate.
2032 if (DomainsActivity.sslIssuedToCName == null) {
2033 // Hide the SSL certificate.
2034 currentSslCardView.setVisibility(View.GONE);
2036 // Show the instruction.
2037 noCurrentWebsiteCertificateTextView.setVisibility(View.VISIBLE);
2039 // Show the SSL certificate.
2040 currentSslCardView.setVisibility(View.VISIBLE);
2042 // Hide the instruction.
2043 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
2046 // Set the status of the radio buttons.
2047 if (savedSslCardView.getVisibility() == View.VISIBLE) { // The saved SSL certificate is displayed.
2048 // Check the saved SSL certificate radio button.
2049 savedSslCertificateRadioButton.setChecked(true);
2051 // Uncheck the current website SSL certificate radio button.
2052 currentWebsiteCertificateRadioButton.setChecked(false);
2054 // Set the background of the saved SSL certificate linear layout to be transparent.
2055 savedSslCertificateLinearLayout.setBackgroundResource(R.color.transparent);
2057 // Darken the background of the current website SSL certificate linear layout according to the theme.
2058 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
2059 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2061 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2064 // Scroll to the current website SSL certificate card.
2065 savedSslCardView.getParent().requestChildFocus(savedSslCardView, savedSslCardView);
2066 } else if (currentSslCardView.getVisibility() == View.VISIBLE) { // The saved SSL certificate is hidden but the current website SSL certificate is visible.
2067 // Check the current website SSL certificate radio button.
2068 currentWebsiteCertificateRadioButton.setChecked(true);
2070 // Uncheck the saved SSL certificate radio button.
2071 savedSslCertificateRadioButton.setChecked(false);
2073 // Set the background of the current website SSL certificate linear layout to be transparent.
2074 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.transparent);
2076 // Darken the background of the saved SSL certificate linear layout according to the theme.
2077 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
2078 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2080 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2083 // Scroll to the current website SSL certificate card.
2084 currentSslCardView.getParent().requestChildFocus(currentSslCardView, currentSslCardView);
2085 } else { // Neither SSL certificate is visible.
2086 // Uncheck both radio buttons.
2087 savedSslCertificateRadioButton.setChecked(false);
2088 currentWebsiteCertificateRadioButton.setChecked(false);
2090 // Scroll to the current website SSL certificate card.
2091 noCurrentWebsiteCertificateTextView.getParent().requestChildFocus(noCurrentWebsiteCertificateTextView, noCurrentWebsiteCertificateTextView);
2093 } else { // SSL certificate pinning is disabled.
2094 // Set the icon according to the theme.
2095 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
2096 pinnedSslCertificateImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.ssl_certificate_disabled_night, null));
2098 pinnedSslCertificateImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.ssl_certificate_disabled_day, null));
2101 // Hide the SSl certificates and instructions.
2102 savedSslCardView.setVisibility(View.GONE);
2103 currentSslCardView.setVisibility(View.GONE);
2104 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
2106 // Uncheck the radio buttons.
2107 savedSslCertificateRadioButton.setChecked(false);
2108 currentWebsiteCertificateRadioButton.setChecked(false);
2112 savedSslCardView.setOnClickListener((View view) -> {
2113 // Check the saved SSL certificate radio button.
2114 savedSslCertificateRadioButton.setChecked(true);
2116 // Uncheck the current website SSL certificate radio button.
2117 currentWebsiteCertificateRadioButton.setChecked(false);
2119 // Set the background of the saved SSL certificate linear layout to be transparent.
2120 savedSslCertificateLinearLayout.setBackgroundResource(R.color.transparent);
2122 // Darken the background of the current website SSL certificate linear layout according to the theme.
2123 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
2124 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2126 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2130 savedSslCertificateRadioButton.setOnClickListener((View view) -> {
2131 // Check the saved SSL certificate radio button.
2132 savedSslCertificateRadioButton.setChecked(true);
2134 // Uncheck the current website SSL certificate radio button.
2135 currentWebsiteCertificateRadioButton.setChecked(false);
2137 // Set the background of the saved SSL certificate linear layout to be transparent.
2138 savedSslCertificateLinearLayout.setBackgroundResource(R.color.transparent);
2140 // Darken the background of the current website SSL certificate linear layout according to the theme.
2141 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
2142 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2144 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2148 currentSslCardView.setOnClickListener((View view) -> {
2149 // Check the current website SSL certificate radio button.
2150 currentWebsiteCertificateRadioButton.setChecked(true);
2152 // Uncheck the saved SSL certificate radio button.
2153 savedSslCertificateRadioButton.setChecked(false);
2155 // Set the background of the current website SSL certificate linear layout to be transparent.
2156 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.transparent);
2158 // Darken the background of the saved SSL certificate linear layout according to the theme.
2159 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
2160 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2162 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2166 currentWebsiteCertificateRadioButton.setOnClickListener((View view) -> {
2167 // Check the current website SSL certificate radio button.
2168 currentWebsiteCertificateRadioButton.setChecked(true);
2170 // Uncheck the saved SSL certificate radio button.
2171 savedSslCertificateRadioButton.setChecked(false);
2173 // Set the background of the current website SSL certificate linear layout to be transparent.
2174 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.transparent);
2176 // Darken the background of the saved SSL certificate linear layout according to the theme.
2177 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
2178 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2180 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2184 // Set the pinned IP addresses switch listener.
2185 pinnedIpAddressesSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
2187 if (isChecked) { // IP addresses pinning is enabled.
2188 // Set the icon according to the theme.
2189 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
2190 pinnedIpAddressesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.ssl_certificate_enabled_night, null));
2192 pinnedIpAddressesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.ssl_certificate_enabled_day, null));
2195 // Update the visibility of the saved IP addresses card view.
2196 if (savedIpAddresses == null) { // There are no saved IP addresses.
2197 savedIpAddressesCardView.setVisibility(View.GONE);
2198 } else { // There are saved IP addresses.
2199 savedIpAddressesCardView.setVisibility(View.VISIBLE);
2202 // Show the current IP addresses card view.
2203 currentIpAddressesCardView.setVisibility(View.VISIBLE);
2205 // Set the status of the radio buttons.
2206 if (savedIpAddressesCardView.getVisibility() == View.VISIBLE) { // The saved IP addresses are visible.
2207 // Check the saved IP addresses radio button.
2208 savedIpAddressesRadioButton.setChecked(true);
2210 // Uncheck the current IP addresses radio button.
2211 currentIpAddressesRadioButton.setChecked(false);
2213 // Set the background of the saved IP addresses linear layout to be transparent.
2214 savedSslCertificateLinearLayout.setBackgroundResource(R.color.transparent);
2216 // Darken the background of the current IP addresses linear layout according to the theme.
2217 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
2218 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2220 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2222 } else { // The saved IP addresses are not visible.
2223 // Check the current IP addresses radio button.
2224 currentIpAddressesRadioButton.setChecked(true);
2226 // Uncheck the saved IP addresses radio button.
2227 savedIpAddressesRadioButton.setChecked(false);
2229 // Set the background of the current IP addresses linear layout to be transparent.
2230 currentIpAddressesLinearLayout.setBackgroundResource(R.color.transparent);
2232 // Darken the background of the saved IP addresses linear layout according to the theme.
2233 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
2234 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2236 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2240 // Scroll to the bottom of the card views.
2241 currentIpAddressesCardView.getParent().requestChildFocus(currentIpAddressesCardView, currentIpAddressesCardView);
2242 } else { // IP addresses pinning is disabled.
2243 // Set the icon according to the theme.
2244 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
2245 pinnedIpAddressesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.ssl_certificate_disabled_night, null));
2247 pinnedIpAddressesImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.ssl_certificate_disabled_day, null));
2250 // Hide the IP addresses card views.
2251 savedIpAddressesCardView.setVisibility(View.GONE);
2252 currentIpAddressesCardView.setVisibility(View.GONE);
2254 // Uncheck the radio buttons.
2255 savedIpAddressesRadioButton.setChecked(false);
2256 currentIpAddressesRadioButton.setChecked(false);
2260 savedIpAddressesCardView.setOnClickListener((View view) -> {
2261 // Check the saved IP addresses radio button.
2262 savedIpAddressesRadioButton.setChecked(true);
2264 // Uncheck the current website IP addresses radio button.
2265 currentIpAddressesRadioButton.setChecked(false);
2267 // Set the background of the saved IP addresses linear layout to be transparent.
2268 savedIpAddressesLinearLayout.setBackgroundResource(R.color.transparent);
2270 // Darken the background of the current IP addresses linear layout according to the theme.
2271 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
2272 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2274 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2278 savedIpAddressesRadioButton.setOnClickListener((View view) -> {
2279 // Check the saved IP addresses radio button.
2280 savedIpAddressesRadioButton.setChecked(true);
2282 // Uncheck the current website IP addresses radio button.
2283 currentIpAddressesRadioButton.setChecked(false);
2285 // Set the background of the saved IP addresses linear layout to be transparent.
2286 savedIpAddressesLinearLayout.setBackgroundResource(R.color.transparent);
2288 // Darken the background of the current IP addresses linear layout according to the theme.
2289 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
2290 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2292 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2296 currentIpAddressesCardView.setOnClickListener((View view) -> {
2297 // Check the current IP addresses radio button.
2298 currentIpAddressesRadioButton.setChecked(true);
2300 // Uncheck the saved IP addresses radio button.
2301 savedIpAddressesRadioButton.setChecked(false);
2303 // Set the background of the current IP addresses linear layout to be transparent.
2304 currentIpAddressesLinearLayout.setBackgroundResource(R.color.transparent);
2306 // Darken the background of the saved IP addresses linear layout according to the theme.
2307 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
2308 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2310 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2314 currentIpAddressesRadioButton.setOnClickListener((View view) -> {
2315 // Check the current IP addresses radio button.
2316 currentIpAddressesRadioButton.setChecked(true);
2318 // Uncheck the saved IP addresses radio button.
2319 savedIpAddressesRadioButton.setChecked(false);
2321 // Set the background of the current IP addresses linear layout to be transparent.
2322 currentIpAddressesLinearLayout.setBackgroundResource(R.color.transparent);
2324 // Darken the background of the saved IP addresses linear layout according to the theme.
2325 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
2326 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2328 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2332 // Set the scroll Y.
2333 domainSettingsScrollView.post(() -> domainSettingsScrollView.setScrollY(scrollY));
2335 // Return the domain settings view.
2336 return domainSettingsView;
2339 private boolean checkDomainNameAgainstCertificate(String domainName, String certificateCommonName) {
2340 // Initialize `domainNamesMatch`.
2341 boolean domainNamesMatch = false;
2343 // Check various wildcard permutations if `domainName` and `certificateCommonName` are not empty.
2344 // `noinspection ConstantCondition` removes Android Studio's incorrect lint warning that `domainName` can never be `null`.
2345 if ((domainName != null) && (certificateCommonName != null)) {
2346 // Check if the domains match.
2347 if (domainName.equals(certificateCommonName)) {
2348 domainNamesMatch = true;
2351 // If `domainName` starts with a wildcard, check the base domain against all the subdomains of `certificateCommonName`.
2352 if (!domainNamesMatch && domainName.startsWith("*.") && (domainName.length() > 2)) {
2353 // Remove the initial `*.`.
2354 String baseDomainName = domainName.substring(2);
2356 // Setup a copy of `certificateCommonName` to test subdomains.
2357 String certificateCommonNameSubdomain = certificateCommonName;
2359 // Check all the subdomains in `certificateCommonNameSubdomain` against `baseDomainName`.
2360 while (!domainNamesMatch && certificateCommonNameSubdomain.contains(".")) { // Stop checking if we know that `domainNamesMatch` is `true` or if we run out of `.`.
2361 // Test the `certificateCommonNameSubdomain` against `baseDomainName`.
2362 if (certificateCommonNameSubdomain.equals(baseDomainName)) {
2363 domainNamesMatch = true;
2366 // Strip out the lowest subdomain of `certificateCommonNameSubdomain`.
2368 certificateCommonNameSubdomain = certificateCommonNameSubdomain.substring(certificateCommonNameSubdomain.indexOf(".") + 1);
2369 } catch (IndexOutOfBoundsException e) { // `certificateCommonNameSubdomain` ends with `.`.
2370 certificateCommonNameSubdomain = "";
2375 // If `certificateCommonName` starts with a wildcard, check the base common name against all the subdomains of `domainName`.
2376 if (!domainNamesMatch && certificateCommonName.startsWith("*.") && (certificateCommonName.length() > 2)) {
2377 // Remove the initial `*.`.
2378 String baseCertificateCommonName = certificateCommonName.substring(2);
2380 // Setup a copy of `domainName` to test subdomains.
2381 String domainNameSubdomain = domainName;
2383 // Check all the subdomains in `domainNameSubdomain` against `baseCertificateCommonName`.
2384 while (!domainNamesMatch && domainNameSubdomain.contains(".") && (domainNameSubdomain.length() > 2)) {
2385 // Test the `domainNameSubdomain` against `baseCertificateCommonName`.
2386 if (domainNameSubdomain.equals(baseCertificateCommonName)) {
2387 domainNamesMatch = true;
2390 // Strip out the lowest subdomain of `domainNameSubdomain`.
2392 domainNameSubdomain = domainNameSubdomain.substring(domainNameSubdomain.indexOf(".") + 1);
2393 } catch (IndexOutOfBoundsException e) { // `domainNameSubdomain` ends with `.`.
2394 domainNameSubdomain = "";
2399 // If both names start with a wildcard, check if the root of one contains the root of the other.
2400 if (!domainNamesMatch && domainName.startsWith("*.") && (domainName.length() > 2) && certificateCommonName.startsWith("*.") && (certificateCommonName.length() > 2)) {
2401 // Remove the wildcards.
2402 String rootDomainName = domainName.substring(2);
2403 String rootCertificateCommonName = certificateCommonName.substring(2);
2405 // Check if one name ends with the contents of the other. If so, there will be overlap in the their wildcard subdomains.
2406 if (rootDomainName.endsWith(rootCertificateCommonName) || rootCertificateCommonName.endsWith(rootDomainName)) {
2407 domainNamesMatch = true;
2412 return domainNamesMatch;