2 * Copyright © 2017-2019 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.Resources;
26 import android.database.Cursor;
27 import android.net.http.SslCertificate;
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.Spinner;
48 import android.widget.Switch;
49 import android.widget.TextView;
51 import androidx.annotation.NonNull;
52 import androidx.cardview.widget.CardView;
53 import androidx.fragment.app.Fragment; // The AndroidX fragment must be used until minimum API >= 23. Otherwise `getContext()` does not work.
55 import com.stoutner.privacybrowser.R;
56 import com.stoutner.privacybrowser.activities.DomainsActivity;
57 import com.stoutner.privacybrowser.activities.MainWebViewActivity;
58 import com.stoutner.privacybrowser.helpers.DomainsDatabaseHelper;
60 import java.text.DateFormat;
61 import java.util.Calendar;
62 import java.util.Date;
64 public class DomainSettingsFragment extends Fragment {
65 // `DATABASE_ID` is used by activities calling this fragment.
66 public static final String DATABASE_ID = "database_id";
68 // `databaseId` is public static so it can be accessed from `DomainsActivity`. It is also used in `onCreate()` and `onCreateView()`.
69 public static int databaseId;
72 public void onCreate(Bundle savedInstanceState) {
73 super.onCreate(savedInstanceState);
75 // Remove the lint warning that `getArguments` might be null.
76 assert getArguments() != null;
78 // Store the database id in `databaseId`.
79 databaseId = getArguments().getInt(DATABASE_ID);
82 // The deprecated `getDrawable()` must be used until the minimum API >= 21.
84 public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
85 // Inflate `domain_settings_fragment`. `false` does not attach it to the root `container`.
86 View domainSettingsView = inflater.inflate(R.layout.domain_settings_fragment, container, false);
88 // Get a handle for the context and the resources.
89 Context context = getContext();
90 final Resources resources = getResources();
92 // Get a handle for the shared preference.
93 SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
95 // Store the default settings.
96 final String defaultUserAgentName = sharedPreferences.getString("user_agent", getString(R.string.user_agent_default_value));
97 final String defaultCustomUserAgentString = sharedPreferences.getString("custom_user_agent", getString(R.string.custom_user_agent_default_value));
98 String defaultFontSizeString = sharedPreferences.getString("font_size", getString(R.string.font_size_default_value));
99 boolean defaultSwipeToRefresh = sharedPreferences.getBoolean("swipe_to_refresh", true);
100 final boolean defaultNightMode = sharedPreferences.getBoolean("night_mode", false);
101 final boolean defaultDisplayWebpageImages = sharedPreferences.getBoolean("display_webpage_images", true);
102 boolean darkTheme = sharedPreferences.getBoolean("dark_theme", false);
104 // Get handles for the views in the fragment.
105 final EditText domainNameEditText = domainSettingsView.findViewById(R.id.domain_settings_name_edittext);
106 final Switch javaScriptEnabledSwitch = domainSettingsView.findViewById(R.id.javascript_switch);
107 final ImageView javaScriptImageView = domainSettingsView.findViewById(R.id.javascript_imageview);
108 Switch firstPartyCookiesEnabledSwitch = domainSettingsView.findViewById(R.id.first_party_cookies_switch);
109 final ImageView firstPartyCookiesImageView = domainSettingsView.findViewById(R.id.first_party_cookies_imageview);
110 LinearLayout thirdPartyCookiesLinearLayout = domainSettingsView.findViewById(R.id.third_party_cookies_linearlayout);
111 final Switch thirdPartyCookiesEnabledSwitch = domainSettingsView.findViewById(R.id.third_party_cookies_switch);
112 final ImageView thirdPartyCookiesImageView = domainSettingsView.findViewById(R.id.third_party_cookies_imageview);
113 final Switch domStorageEnabledSwitch = domainSettingsView.findViewById(R.id.dom_storage_switch);
114 final ImageView domStorageImageView = domainSettingsView.findViewById(R.id.dom_storage_imageview);
115 Switch formDataEnabledSwitch = domainSettingsView.findViewById(R.id.form_data_switch); // The form data views can be remove once the minimum API >= 26.
116 final ImageView formDataImageView = domainSettingsView.findViewById(R.id.form_data_imageview); // The form data views can be remove once the minimum API >= 26.
117 Switch easyListSwitch = domainSettingsView.findViewById(R.id.easylist_switch);
118 ImageView easyListImageView = domainSettingsView.findViewById(R.id.easylist_imageview);
119 Switch easyPrivacySwitch = domainSettingsView.findViewById(R.id.easyprivacy_switch);
120 ImageView easyPrivacyImageView = domainSettingsView.findViewById(R.id.easyprivacy_imageview);
121 Switch fanboysAnnoyanceListSwitch = domainSettingsView.findViewById(R.id.fanboys_annoyance_list_switch);
122 ImageView fanboysAnnoyanceListImageView = domainSettingsView.findViewById(R.id.fanboys_annoyance_list_imageview);
123 Switch fanboysSocialBlockingListSwitch = domainSettingsView.findViewById(R.id.fanboys_social_blocking_list_switch);
124 ImageView fanboysSocialBlockingListImageView = domainSettingsView.findViewById(R.id.fanboys_social_blocking_list_imageview);
125 Switch ultraPrivacySwitch = domainSettingsView.findViewById(R.id.ultraprivacy_switch);
126 ImageView ultraPrivacyImageView = domainSettingsView.findViewById(R.id.ultraprivacy_imageview);
127 Switch blockAllThirdPartyRequestsSwitch = domainSettingsView.findViewById(R.id.block_all_third_party_requests_switch);
128 ImageView blockAllThirdPartyRequestsImageView = domainSettingsView.findViewById(R.id.block_all_third_party_requests_imageview);
129 final Spinner userAgentSpinner = domainSettingsView.findViewById(R.id.user_agent_spinner);
130 final TextView userAgentTextView = domainSettingsView.findViewById(R.id.user_agent_textview);
131 final EditText customUserAgentEditText = domainSettingsView.findViewById(R.id.custom_user_agent_edittext);
132 final Spinner fontSizeSpinner = domainSettingsView.findViewById(R.id.font_size_spinner);
133 final TextView fontSizeTextView = domainSettingsView.findViewById(R.id.font_size_textview);
134 final ImageView swipeToRefreshImageView = domainSettingsView.findViewById(R.id.swipe_to_refresh_imageview);
135 final Spinner swipeToRefreshSpinner = domainSettingsView.findViewById(R.id.swipe_to_refresh_spinner);
136 final TextView swipeToRefreshTextView = domainSettingsView.findViewById(R.id.swipe_to_refresh_textview);
137 final ImageView nightModeImageView = domainSettingsView.findViewById(R.id.night_mode_imageview);
138 final Spinner nightModeSpinner = domainSettingsView.findViewById(R.id.night_mode_spinner);
139 final TextView nightModeTextView = domainSettingsView.findViewById(R.id.night_mode_textview);
140 final ImageView displayWebpageImagesImageView = domainSettingsView.findViewById(R.id.display_webpage_images_imageview);
141 final Spinner displayWebpageImagesSpinner = domainSettingsView.findViewById(R.id.display_webpage_images_spinner);
142 final TextView displayImagesTextView = domainSettingsView.findViewById(R.id.display_webpage_images_textview);
143 final ImageView pinnedSslCertificateImageView = domainSettingsView.findViewById(R.id.pinned_ssl_certificate_imageview);
144 Switch pinnedSslCertificateSwitch = domainSettingsView.findViewById(R.id.pinned_ssl_certificate_switch);
145 final CardView savedSslCertificateCardView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_cardview);
146 LinearLayout savedSslCertificateLinearLayout = domainSettingsView.findViewById(R.id.saved_ssl_certificate_linearlayout);
147 final RadioButton savedSslCertificateRadioButton = domainSettingsView.findViewById(R.id.saved_ssl_certificate_radiobutton);
148 final TextView savedSslCertificateIssuedToCNameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_to_cname);
149 TextView savedSslCertificateIssuedToONameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_to_oname);
150 TextView savedSslCertificateIssuedToUNameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_to_uname);
151 TextView savedSslCertificateIssuedByCNameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_by_cname);
152 TextView savedSslCertificateIssuedByONameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_by_oname);
153 TextView savedSslCertificateIssuedByUNameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_by_uname);
154 TextView savedSslCertificateStartDateTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_start_date);
155 TextView savedSslCertificateEndDateTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_end_date);
156 final CardView currentWebsiteCertificateCardView = domainSettingsView.findViewById(R.id.current_website_certificate_cardview);
157 LinearLayout currentWebsiteCertificateLinearLayout = domainSettingsView.findViewById(R.id.current_website_certificate_linearlayout);
158 final RadioButton currentWebsiteCertificateRadioButton = domainSettingsView.findViewById(R.id.current_website_certificate_radiobutton);
159 final TextView currentWebsiteCertificateIssuedToCNameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_to_cname);
160 TextView currentWebsiteCertificateIssuedToONameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_to_oname);
161 TextView currentWebsiteCertificateIssuedToUNameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_to_uname);
162 TextView currentWebsiteCertificateIssuedByCNameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_by_cname);
163 TextView currentWebsiteCertificateIssuedByONameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_by_oname);
164 TextView currentWebsiteCertificateIssuedByUNameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_by_uname);
165 TextView currentWebsiteCertificateStartDateTextView = domainSettingsView.findViewById(R.id.current_website_certificate_start_date);
166 TextView currentWebsiteCertificateEndDateTextView = domainSettingsView.findViewById(R.id.current_website_certificate_end_date);
167 final TextView noCurrentWebsiteCertificateTextView = domainSettingsView.findViewById(R.id.no_current_website_certificate);
168 ImageView pinnedIpAddressesImageView = domainSettingsView.findViewById(R.id.pinned_ip_addresses_imageview);
169 Switch pinnedIpAddressesSwitch = domainSettingsView.findViewById(R.id.pinned_ip_addresses_switch);
170 CardView savedIpAddressesCardView = domainSettingsView.findViewById(R.id.saved_ip_addresses_cardview);
171 LinearLayout savedIpAddressesLinearLayout = domainSettingsView.findViewById(R.id.saved_ip_addresses_linearlayout);
172 RadioButton savedIpAddressesRadioButton = domainSettingsView.findViewById(R.id.saved_ip_addresses_radiobutton);
173 TextView savedIpAddressesTextView = domainSettingsView.findViewById(R.id.saved_ip_addresses_textview);
174 CardView currentIpAddressesCardView = domainSettingsView.findViewById(R.id.current_ip_addresses_cardview);
175 LinearLayout currentIpAddressesLinearLayout = domainSettingsView.findViewById(R.id.current_ip_addresses_linearlayout);
176 RadioButton currentIpAddressesRadioButton = domainSettingsView.findViewById(R.id.current_ip_addresses_radiobutton);
177 TextView currentIpAddressesTextView = domainSettingsView.findViewById(R.id.current_ip_addresses_textview);
179 // Setup the pinned labels.
180 String cNameLabel = getString(R.string.common_name) + " ";
181 String oNameLabel = getString(R.string.organization) + " ";
182 String uNameLabel = getString(R.string.organizational_unit) + " ";
183 String startDateLabel = getString(R.string.start_date) + " ";
184 String endDateLabel = getString(R.string.end_date) + " ";
186 // Get the current website SSL certificate
187 final SslCertificate currentWebsiteSslCertificate = DomainsActivity.currentSslCertificate;
189 // Initialize the database handler. The `0` specifies the database version, but that is ignored and set instead using a constant in `DomainsDatabaseHelper`.
190 DomainsDatabaseHelper domainsDatabaseHelper = new DomainsDatabaseHelper(context, null, null, 0);
192 // Get the database cursor for this ID and move it to the first row.
193 Cursor domainCursor = domainsDatabaseHelper.getCursorForId(databaseId);
194 domainCursor.moveToFirst();
196 // Save the cursor entries as variables.
197 String domainNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.DOMAIN_NAME));
198 final int javaScriptEnabledInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_JAVASCRIPT));
199 int firstPartyCookiesEnabledInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FIRST_PARTY_COOKIES));
200 int thirdPartyCookiesEnabledInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_THIRD_PARTY_COOKIES));
201 final int domStorageEnabledInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_DOM_STORAGE));
202 int formDataEnabledInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FORM_DATA)); // Form data can be remove once the minimum API >= 26.
203 int easyListEnabledInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_EASYLIST));
204 int easyPrivacyEnabledInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_EASYPRIVACY));
205 int fanboysAnnoyanceListInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FANBOYS_ANNOYANCE_LIST));
206 int fanboysSocialBlockingListInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FANBOYS_SOCIAL_BLOCKING_LIST));
207 int ultraPrivacyEnabledInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_ULTRAPRIVACY));
208 int blockAllThirdPartyRequestsInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.BLOCK_ALL_THIRD_PARTY_REQUESTS));
209 final String currentUserAgentName = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.USER_AGENT));
210 int fontSizeInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.FONT_SIZE));
211 int swipeToRefreshInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.SWIPE_TO_REFRESH));
212 int nightModeInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.NIGHT_MODE));
213 int displayImagesInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.DISPLAY_IMAGES));
214 int pinnedSslCertificateInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.PINNED_SSL_CERTIFICATE));
215 String savedSslCertificateIssuedToCNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_TO_COMMON_NAME));
216 String savedSslCertificateIssuedToONameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_TO_ORGANIZATION));
217 String savedSslCertificateIssuedToUNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_TO_ORGANIZATIONAL_UNIT));
218 String savedSslCertificateIssuedByCNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_BY_COMMON_NAME));
219 String savedSslCertificateIssuedByONameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_BY_ORGANIZATION));
220 String savedSslCertificateIssuedByUNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_BY_ORGANIZATIONAL_UNIT));
221 int pinnedIpAddressesInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.PINNED_IP_ADDRESSES));
222 String savedIpAddresses = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.IP_ADDRESSES));
224 // Initialize the saved SSL certificate date variables.
225 Date savedSslCertificateStartDate = null;
226 Date savedSslCertificateEndDate = null;
228 // Only get the saved SSL certificate dates from the cursor if they are not set to `0`.
229 if (domainCursor.getLong(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_START_DATE)) != 0) {
230 savedSslCertificateStartDate = new Date(domainCursor.getLong(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_START_DATE)));
233 if (domainCursor.getLong(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_END_DATE)) != 0) {
234 savedSslCertificateEndDate = new Date(domainCursor.getLong(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_END_DATE)));
237 // Create array adapters for the spinners.
238 ArrayAdapter<CharSequence> translatedUserAgentArrayAdapter = ArrayAdapter.createFromResource(context, R.array.translated_domain_settings_user_agent_names, R.layout.spinner_item);
239 ArrayAdapter<CharSequence> fontSizeArrayAdapter = ArrayAdapter.createFromResource(context, R.array.domain_settings_font_size_entries, R.layout.spinner_item);
240 ArrayAdapter<CharSequence> fontSizeEntryValuesArrayAdapter = ArrayAdapter.createFromResource(context, R.array.domain_settings_font_size_entry_values, R.layout.spinner_item);
241 ArrayAdapter<CharSequence> swipeToRefreshArrayAdapter = ArrayAdapter.createFromResource(context, R.array.swipe_to_refresh_array, R.layout.spinner_item);
242 ArrayAdapter<CharSequence> nightModeArrayAdapter = ArrayAdapter.createFromResource(context, R.array.night_mode_array, R.layout.spinner_item);
243 ArrayAdapter<CharSequence> displayImagesArrayAdapter = ArrayAdapter.createFromResource(context, R.array.display_webpage_images_array, R.layout.spinner_item);
245 // Set the drop down view resource on the spinners.
246 translatedUserAgentArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items);
247 fontSizeArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items);
248 swipeToRefreshArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items);
249 nightModeArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items);
250 displayImagesArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items);
252 // Set the array adapters for the spinners.
253 userAgentSpinner.setAdapter(translatedUserAgentArrayAdapter);
254 fontSizeSpinner.setAdapter(fontSizeArrayAdapter);
255 swipeToRefreshSpinner.setAdapter(swipeToRefreshArrayAdapter);
256 nightModeSpinner.setAdapter(nightModeArrayAdapter);
257 displayWebpageImagesSpinner.setAdapter(displayImagesArrayAdapter);
259 // Create a spannable string builder for each TextView that needs multiple colors of text.
260 SpannableStringBuilder savedSslCertificateIssuedToCNameStringBuilder = new SpannableStringBuilder(cNameLabel + savedSslCertificateIssuedToCNameString);
261 SpannableStringBuilder savedSslCertificateIssuedToONameStringBuilder = new SpannableStringBuilder(oNameLabel + savedSslCertificateIssuedToONameString);
262 SpannableStringBuilder savedSslCertificateIssuedToUNameStringBuilder = new SpannableStringBuilder(uNameLabel + savedSslCertificateIssuedToUNameString);
263 SpannableStringBuilder savedSslCertificateIssuedByCNameStringBuilder = new SpannableStringBuilder(cNameLabel + savedSslCertificateIssuedByCNameString);
264 SpannableStringBuilder savedSslCertificateIssuedByONameStringBuilder = new SpannableStringBuilder(oNameLabel + savedSslCertificateIssuedByONameString);
265 SpannableStringBuilder savedSslCertificateIssuedByUNameStringBuilder = new SpannableStringBuilder(uNameLabel + savedSslCertificateIssuedByUNameString);
267 // Initialize the spannable string builders for the SSL certificate dates.
268 SpannableStringBuilder savedSslCertificateStartDateStringBuilder;
269 SpannableStringBuilder savedSslCertificateEndDateStringBuilder;
271 // Leave the SSL certificate dates empty if they are `null`.
272 if (savedSslCertificateStartDate == null) {
273 savedSslCertificateStartDateStringBuilder = new SpannableStringBuilder(startDateLabel);
275 savedSslCertificateStartDateStringBuilder = new SpannableStringBuilder(startDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(savedSslCertificateStartDate));
278 if (savedSslCertificateEndDate == null) {
279 savedSslCertificateEndDateStringBuilder = new SpannableStringBuilder(endDateLabel);
281 savedSslCertificateEndDateStringBuilder = new SpannableStringBuilder(endDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(savedSslCertificateEndDate));
284 // Create a red foreground color span. The deprecated `resources.getColor` must be used until the minimum API >= 23.
285 final ForegroundColorSpan redColorSpan = new ForegroundColorSpan(resources.getColor(R.color.red_a700));
287 // Create a blue foreground color span.
288 final ForegroundColorSpan blueColorSpan;
290 // Set the blue color span according to the theme. The deprecated `resources.getColor` must be used until the minimum API >= 23.
292 //noinspection deprecation
293 blueColorSpan = new ForegroundColorSpan(resources.getColor(R.color.blue_400));
295 //noinspection deprecation
296 blueColorSpan = new ForegroundColorSpan(resources.getColor(R.color.blue_700));
299 // Set the domain name from the the database cursor.
300 domainNameEditText.setText(domainNameString);
302 // Update the certificates' `Common Name` color when the domain name text changes.
303 domainNameEditText.addTextChangedListener(new TextWatcher() {
305 public void beforeTextChanged(CharSequence s, int start, int count, int after) {
310 public void onTextChanged(CharSequence s, int start, int before, int count) {
315 public void afterTextChanged(Editable s) {
316 // Get the new domain name.
317 String newDomainName = domainNameEditText.getText().toString();
319 // Check the saved SSL certificate against the new domain name.
320 boolean savedSslCertificateMatchesNewDomainName = checkDomainNameAgainstCertificate(newDomainName, savedSslCertificateIssuedToCNameString);
322 // Create a `SpannableStringBuilder` for the saved certificate `Common Name`.
323 SpannableStringBuilder savedSslCertificateCommonNameStringBuilder = new SpannableStringBuilder(cNameLabel + savedSslCertificateIssuedToCNameString);
325 // Format the saved certificate `Common Name` color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
326 if (savedSslCertificateMatchesNewDomainName) {
327 savedSslCertificateCommonNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), savedSslCertificateCommonNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
329 savedSslCertificateCommonNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), savedSslCertificateCommonNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
332 // Update `savedSslCertificateIssuedToCNameTextView`.
333 savedSslCertificateIssuedToCNameTextView.setText(savedSslCertificateCommonNameStringBuilder);
335 // Update the current website certificate if it exists.
336 if (currentWebsiteSslCertificate != null) {
337 // Get the current website certificate `Common Name`.
338 String currentWebsiteCertificateCommonName = currentWebsiteSslCertificate.getIssuedTo().getCName();
340 // Check the current website certificate against the new domain name.
341 boolean currentWebsiteCertificateMatchesNewDomainName = checkDomainNameAgainstCertificate(newDomainName, currentWebsiteCertificateCommonName);
343 // Create a `SpannableStringBuilder` for the current website certificate `Common Name`.
344 SpannableStringBuilder currentWebsiteCertificateCommonNameStringBuilder = new SpannableStringBuilder(cNameLabel + currentWebsiteCertificateCommonName);
346 // Format the current certificate `Common Name` color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
347 if (currentWebsiteCertificateMatchesNewDomainName) {
348 currentWebsiteCertificateCommonNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), currentWebsiteCertificateCommonNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
350 currentWebsiteCertificateCommonNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), currentWebsiteCertificateCommonNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
353 // Update `currentWebsiteCertificateIssuedToCNameTextView`.
354 currentWebsiteCertificateIssuedToCNameTextView.setText(currentWebsiteCertificateCommonNameStringBuilder);
359 // Create a boolean to track if night mode is enabled.
360 boolean nightModeEnabled = (nightModeInt == DomainsDatabaseHelper.NIGHT_MODE_ENABLED) || ((nightModeInt == DomainsDatabaseHelper.NIGHT_MODE_SYSTEM_DEFAULT) && defaultNightMode);
362 // Disable the JavaScript switch if night mode is enabled.
363 if (nightModeEnabled) {
364 javaScriptEnabledSwitch.setEnabled(false);
366 javaScriptEnabledSwitch.setEnabled(true);
369 // Set the JavaScript icon.
370 if ((javaScriptEnabledInt == 1) || nightModeEnabled) {
371 javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.javascript_enabled));
373 javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.privacy_mode));
376 // Set the JavaScript switch status.
377 if (javaScriptEnabledInt == 1) { // JavaScript is enabled.
378 javaScriptEnabledSwitch.setChecked(true);
379 } else { // JavaScript is disabled.
380 javaScriptEnabledSwitch.setChecked(false);
383 // 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.
384 if (firstPartyCookiesEnabledInt == 1) { // First-party cookies are enabled.
385 firstPartyCookiesEnabledSwitch.setChecked(true);
386 firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_enabled));
387 } else { // First-party cookies are disabled.
388 firstPartyCookiesEnabledSwitch.setChecked(false);
390 // Set the icon according to the theme.
392 firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_dark));
394 firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_light));
398 // Only display third-party cookies if SDK_INT >= 21.
399 if (Build.VERSION.SDK_INT >= 21) { // Third-party cookies can be configured for API >= 21.
400 // Only enable third-party-cookies if first-party cookies are enabled.
401 if (firstPartyCookiesEnabledInt == 1) { // First-party cookies are enabled.
402 // 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.
403 if (thirdPartyCookiesEnabledInt == 1) { // Both first-party and third-party cookies are enabled.
404 thirdPartyCookiesEnabledSwitch.setChecked(true);
405 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_warning));
406 } else { // First party cookies are enabled but third-party cookies are disabled.
407 thirdPartyCookiesEnabledSwitch.setChecked(false);
409 // Set the icon according to the theme.
411 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_dark));
413 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_light));
416 } else { // First-party cookies are disabled.
417 // Set the status of third-party cookies.
418 if (thirdPartyCookiesEnabledInt == 1) {
419 thirdPartyCookiesEnabledSwitch.setChecked(true);
421 thirdPartyCookiesEnabledSwitch.setChecked(false);
424 // Disable the third-party cookies switch.
425 thirdPartyCookiesEnabledSwitch.setEnabled(false);
427 // Set the icon according to the theme.
429 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_ghosted_dark));
431 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_ghosted_light));
434 } else { // Third-party cookies cannot be configured for API <= 21.
435 // Hide the LinearLayout for third-party cookies.
436 thirdPartyCookiesLinearLayout.setVisibility(View.GONE);
439 // Only enable DOM storage if JavaScript is enabled.
440 if ((javaScriptEnabledInt == 1) || nightModeEnabled) { // JavaScript is enabled.
441 // Enable the DOM storage `Switch`.
442 domStorageEnabledSwitch.setEnabled(true);
444 // Set the DOM storage status. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
445 if (domStorageEnabledInt == 1) { // Both JavaScript and DOM storage are enabled.
446 domStorageEnabledSwitch.setChecked(true);
447 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_enabled));
448 } else { // JavaScript is enabled but DOM storage is disabled.
449 // Set the DOM storage switch to off.
450 domStorageEnabledSwitch.setChecked(false);
452 // Set the icon according to the theme.
454 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_dark));
456 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_light));
459 } else { // JavaScript is disabled.
460 // Disable the DOM storage `Switch`.
461 domStorageEnabledSwitch.setEnabled(false);
463 // Set the checked status of DOM storage.
464 if (domStorageEnabledInt == 1) { // DOM storage is enabled but JavaScript is disabled.
465 domStorageEnabledSwitch.setChecked(true);
466 } else { // Both JavaScript and DOM storage are disabled.
467 domStorageEnabledSwitch.setChecked(false);
470 // Set the icon according to the theme.
472 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_dark));
474 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_light));
478 // Set the form data status. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons. Form data can be removed once the minimum API >= 26.
479 if (Build.VERSION.SDK_INT >= 26) { // Form data no longer applies to newer versions of Android.
480 // Hide the form data switch.
481 formDataEnabledSwitch.setVisibility(View.GONE);
482 } else { // Form data should be displayed because this is an older version of Android.
483 if (formDataEnabledInt == 1) { // Form data is on.
484 formDataEnabledSwitch.setChecked(true);
485 formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_enabled));
486 } else { // Form data is off.
487 // Turn the form data switch to off.
488 formDataEnabledSwitch.setChecked(false);
490 // Set the icon according to the theme.
492 formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_disabled_dark));
494 formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_disabled_light));
499 // Set the EasyList status. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
500 if (easyListEnabledInt == 1) { // EasyList is on.
501 // Turn the switch on.
502 easyListSwitch.setChecked(true);
504 // Set the icon according to the theme.
506 easyListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_enabled_dark));
508 easyListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_enabled_light));
510 } else { // EasyList is off.
511 // Turn the switch off.
512 easyListSwitch.setChecked(false);
514 // Set the icon according to the theme.
516 easyListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_disabled_dark));
518 easyListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_disabled_light));
522 // Set the EasyPrivacy status. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
523 if (easyPrivacyEnabledInt == 1) { // EasyPrivacy is on.
524 // Turn the switch on.
525 easyPrivacySwitch.setChecked(true);
527 // Set the icon according to the theme.
529 easyPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_enabled_dark));
531 easyPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_enabled_light));
533 } else { // EasyPrivacy is off.
534 // Turn the switch off.
535 easyPrivacySwitch.setChecked(false);
537 // Set the icon according to the theme.
539 easyPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_disabled_dark));
541 easyPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_disabled_light));
545 // 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.
546 if (fanboysAnnoyanceListInt == 1) { // Fanboy's Annoyance List is on.
547 // Turn the switch on.
548 fanboysAnnoyanceListSwitch.setChecked(true);
550 // Set the icon according to the theme.
552 fanboysAnnoyanceListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_dark));
554 fanboysAnnoyanceListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_light));
556 } else { // Fanboy's Annoyance List is off.
557 // Turn the switch off.
558 fanboysAnnoyanceListSwitch.setChecked(false);
560 // Set the icon according to the theme.
562 fanboysAnnoyanceListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_dark));
564 fanboysAnnoyanceListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_light));
568 // Only enable Fanboy's Social Blocking List if Fanboy's Annoyance List is off.
569 if (fanboysAnnoyanceListInt == 0) { // Fanboy's Annoyance List is on.
570 // 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.
571 if (fanboysSocialBlockingListInt == 1) { // Fanboy's Social Blocking List is on.
572 // Enable the switch and turn it on.
573 fanboysSocialBlockingListSwitch.setEnabled(true);
574 fanboysSocialBlockingListSwitch.setChecked(true);
576 // Set the icon according to the theme.
578 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_dark));
580 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_light));
582 } else { // Fanboy's Social Blocking List is off.
583 // Enable the switch but turn it off.
584 fanboysSocialBlockingListSwitch.setEnabled(true);
585 fanboysSocialBlockingListSwitch.setChecked(false);
587 // Set the icon according to the theme.
589 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_dark));
591 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_light));
594 } else { // Fanboy's Annoyance List is on.
595 // Disable Fanboy's Social Blocking List. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
596 if (fanboysSocialBlockingListInt == 1) { // Fanboy's Social Blocking List is on.
597 // Disable the switch but turn it on.
598 fanboysSocialBlockingListSwitch.setEnabled(false);
599 fanboysSocialBlockingListSwitch.setChecked(true);
600 } else { // Fanboy's Social Blocking List is off.
601 // Disable the switch and turn it off.
602 fanboysSocialBlockingListSwitch.setEnabled(false);
603 fanboysSocialBlockingListSwitch.setChecked(false);
606 // Set the icon according to the theme.
608 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_ghosted_dark));
610 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_ghosted_light));
614 // Set the UltraPrivacy status. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
615 if (ultraPrivacyEnabledInt == 1) { // UltraPrivacy is on.
616 // Turn the switch on.
617 ultraPrivacySwitch.setChecked(true);
619 // Set the icon according to the theme.
621 ultraPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_enabled_dark));
623 ultraPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_enabled_light));
625 } else { // EasyPrivacy is off.
626 // Turn the switch off.
627 ultraPrivacySwitch.setChecked(false);
629 // Set the icon according to the theme.
631 ultraPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_disabled_dark));
633 ultraPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_disabled_light));
637 // 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.
638 if (blockAllThirdPartyRequestsInt == 1) { // Blocking all third-party requests is on.
639 // Turn the switch on.
640 blockAllThirdPartyRequestsSwitch.setChecked(true);
642 // Set the icon according to the theme.
644 blockAllThirdPartyRequestsImageView.setImageDrawable(resources.getDrawable(R.drawable.block_all_third_party_requests_enabled_dark));
646 blockAllThirdPartyRequestsImageView.setImageDrawable(resources.getDrawable(R.drawable.block_all_third_party_requests_enabled_light));
648 } else { // Blocking all third-party requests is off.
649 // Turn the switch off.
650 blockAllThirdPartyRequestsSwitch.setChecked(false);
652 // Set the icon according to the theme.
654 blockAllThirdPartyRequestsImageView.setImageDrawable(resources.getDrawable(R.drawable.block_all_third_party_requests_disabled_dark));
656 blockAllThirdPartyRequestsImageView.setImageDrawable(resources.getDrawable(R.drawable.block_all_third_party_requests_disabled_light));
660 // Inflated a WebView to get the default user agent.
661 // `@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.
662 @SuppressLint("InflateParams") View bareWebViewLayout = inflater.inflate(R.layout.bare_webview, null, false);
663 WebView bareWebView = bareWebViewLayout.findViewById(R.id.bare_webview);
664 final String webViewDefaultUserAgentString = bareWebView.getSettings().getUserAgentString();
666 // Get a handle for the user agent array adapter. This array does not contain the `System default` entry.
667 ArrayAdapter<CharSequence> userAgentNamesArray = ArrayAdapter.createFromResource(context, R.array.user_agent_names, R.layout.spinner_item);
669 // Get the positions of the user agent and the default user agent.
670 int userAgentArrayPosition = userAgentNamesArray.getPosition(currentUserAgentName);
671 int defaultUserAgentArrayPosition = userAgentNamesArray.getPosition(defaultUserAgentName);
673 // Get a handle for the user agent data array. This array does not contain the `System default` entry.
674 String[] userAgentDataArray = resources.getStringArray(R.array.user_agent_data);
676 // Set the user agent text.
677 if (currentUserAgentName.equals(getString(R.string.system_default_user_agent))) { // Use the system default user agent.
678 // Set the user agent according to the system default.
679 switch (defaultUserAgentArrayPosition) {
680 case MainWebViewActivity.UNRECOGNIZED_USER_AGENT: // The default user agent name is not on the canonical list.
681 // This is probably because it was set in an older version of Privacy Browser before the switch to persistent user agent names.
682 userAgentTextView.setText(defaultUserAgentName);
685 case MainWebViewActivity.SETTINGS_WEBVIEW_DEFAULT_USER_AGENT:
686 // Display the `WebView` default user agent.
687 userAgentTextView.setText(webViewDefaultUserAgentString);
690 case MainWebViewActivity.SETTINGS_CUSTOM_USER_AGENT:
691 // Display the custom user agent.
692 userAgentTextView.setText(defaultCustomUserAgentString);
696 // Get the user agent string from the user agent data array.
697 userAgentTextView.setText(userAgentDataArray[defaultUserAgentArrayPosition]);
699 } else if (userAgentArrayPosition == MainWebViewActivity.UNRECOGNIZED_USER_AGENT) { // A custom user agent is stored in the current user agent name.
700 // Set the user agent spinner to `Custom user agent`.
701 userAgentSpinner.setSelection(MainWebViewActivity.DOMAINS_CUSTOM_USER_AGENT);
703 // Hide the user agent TextView.
704 userAgentTextView.setVisibility(View.GONE);
706 // Show the custom user agent EditText and set the current user agent name as the text.
707 customUserAgentEditText.setVisibility(View.VISIBLE);
708 customUserAgentEditText.setText(currentUserAgentName);
709 } else { // The user agent name contains one of the canonical user agents.
710 // 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.
711 userAgentSpinner.setSelection(userAgentArrayPosition + 1);
713 // Show the user agent TextView.
714 userAgentTextView.setVisibility(View.VISIBLE);
716 // Hide the custom user agent EditText.
717 customUserAgentEditText.setVisibility(View.GONE);
719 // Set the user agent text.
720 switch (userAgentArrayPosition) {
721 case MainWebViewActivity.DOMAINS_WEBVIEW_DEFAULT_USER_AGENT:
722 // Display the WebView default user agent.
723 userAgentTextView.setText(webViewDefaultUserAgentString);
727 // 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.
728 userAgentTextView.setText(userAgentDataArray[userAgentArrayPosition + 1]);
732 // Open the user agent spinner when the TextView is clicked.
733 userAgentTextView.setOnClickListener((View v) -> {
734 // Open the user agent spinner.
735 userAgentSpinner.performClick();
738 // Set the selected font size.
739 int fontSizeArrayPosition = fontSizeEntryValuesArrayAdapter.getPosition(String.valueOf(fontSizeInt));
740 fontSizeSpinner.setSelection(fontSizeArrayPosition);
742 // Set the default font size text.
743 int defaultFontSizeArrayPosition = fontSizeEntryValuesArrayAdapter.getPosition(defaultFontSizeString);
744 fontSizeTextView.setText(fontSizeArrayAdapter.getItem(defaultFontSizeArrayPosition));
746 // Set the display options for the font size TextView.
747 if (fontSizeArrayPosition == 0) { // System default font size is selected. Display `fontSizeTextView`.
748 fontSizeTextView.setVisibility(View.VISIBLE);
749 } else { // A custom font size is specified. Hide `fontSizeTextView`.
750 fontSizeTextView.setVisibility(View.GONE);
753 // Open the font size spinner when the TextView is clicked.
754 fontSizeTextView.setOnClickListener((View v) -> {
755 // Open the user agent spinner.
756 fontSizeSpinner.performClick();
759 // Display the swipe to refresh selection in the spinner.
760 swipeToRefreshSpinner.setSelection(swipeToRefreshInt);
762 // Set the swipe to refresh text.
763 if (defaultSwipeToRefresh) {
764 swipeToRefreshTextView.setText(swipeToRefreshArrayAdapter.getItem(DomainsDatabaseHelper.SWIPE_TO_REFRESH_ENABLED));
766 swipeToRefreshTextView.setText(swipeToRefreshArrayAdapter.getItem(DomainsDatabaseHelper.SWIPE_TO_REFRESH_DISABLED));
769 // 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.
770 switch (swipeToRefreshInt) {
771 case DomainsDatabaseHelper.SWIPE_TO_REFRESH_SYSTEM_DEFAULT:
772 if (defaultSwipeToRefresh) { // Swipe to refresh is enabled by default.
773 // Set the icon according to the theme.
775 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_enabled_dark));
777 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_enabled_light));
779 } else { // Swipe to refresh is disabled by default
780 // Set the icon according to the theme.
782 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_disabled_dark));
784 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_disabled_light));
788 // Show the swipe to refresh TextView.
789 swipeToRefreshTextView.setVisibility(View.VISIBLE);
792 case DomainsDatabaseHelper.SWIPE_TO_REFRESH_ENABLED:
793 // Set the icon according to the theme.
795 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_enabled_dark));
797 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_enabled_light));
800 // Hide the swipe to refresh TextView.`
801 swipeToRefreshTextView.setVisibility(View.GONE);
804 case DomainsDatabaseHelper.SWIPE_TO_REFRESH_DISABLED:
805 // Set the icon according to the theme.
807 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_disabled_dark));
809 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_disabled_light));
812 // Hide the swipe to refresh TextView.
813 swipeToRefreshTextView.setVisibility(View.GONE);
816 // Open the swipe to refresh spinner when the TextView is clicked.
817 swipeToRefreshTextView.setOnClickListener((View v) -> {
818 // Open the swipe to refresh spinner.
819 swipeToRefreshSpinner.performClick();
822 // Display the night mode in the spinner.
823 nightModeSpinner.setSelection(nightModeInt);
825 // Set the default night mode text.
826 if (defaultNightMode) {
827 nightModeTextView.setText(nightModeArrayAdapter.getItem(DomainsDatabaseHelper.NIGHT_MODE_ENABLED));
829 nightModeTextView.setText(nightModeArrayAdapter.getItem(DomainsDatabaseHelper.NIGHT_MODE_DISABLED));
832 // Set the night mode icon and TextView settings. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
833 switch (nightModeInt) {
834 case DomainsDatabaseHelper.NIGHT_MODE_SYSTEM_DEFAULT:
835 if (defaultNightMode) { // Night mode enabled by default.
836 // Set the icon according to the theme.
838 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_dark));
840 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_light));
842 } else { // Night mode disabled by default.
843 // Set the icon according to the theme.
845 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_dark));
847 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_light));
851 // Show night mode TextView.
852 nightModeTextView.setVisibility(View.VISIBLE);
855 case DomainsDatabaseHelper.NIGHT_MODE_ENABLED:
856 // Set the icon according to the theme.
858 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_dark));
860 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_light));
863 // Hide the night mode TextView.
864 nightModeTextView.setVisibility(View.GONE);
867 case DomainsDatabaseHelper.NIGHT_MODE_DISABLED:
868 // Set the icon according to the theme.
870 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_dark));
872 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_light));
875 // Hide the night mode TextView.
876 nightModeTextView.setVisibility(View.GONE);
880 // Open the night mode spinner when the TextView is clicked.
881 nightModeTextView.setOnClickListener((View v) -> {
882 // Open the night mode spinner.
883 nightModeSpinner.performClick();
886 // Display the website images mode in the spinner.
887 displayWebpageImagesSpinner.setSelection(displayImagesInt);
889 // Set the default display images text.
890 if (defaultDisplayWebpageImages) {
891 displayImagesTextView.setText(displayImagesArrayAdapter.getItem(DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_ENABLED));
893 displayImagesTextView.setText(displayImagesArrayAdapter.getItem(DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_DISABLED));
896 // Set the display website images icon and TextView settings. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
897 switch (displayImagesInt) {
898 case DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_SYSTEM_DEFAULT:
899 if (defaultDisplayWebpageImages) { // Display webpage images enabled by default.
900 // Set the icon according to the theme.
902 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_dark));
904 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_light));
906 } else { // Display webpage images disabled by default.
907 // Set the icon according to the theme.
909 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_dark));
911 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_light));
915 // Show the display images TextView.
916 displayImagesTextView.setVisibility(View.VISIBLE);
919 case DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_ENABLED:
920 // Set the icon according to the theme.
922 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_dark));
924 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_light));
927 // Hide the display images TextView.
928 displayImagesTextView.setVisibility(View.GONE);
931 case DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_DISABLED:
932 // Set the icon according to the theme.
934 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_dark));
936 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_light));
939 // Hide the display images TextView.
940 displayImagesTextView.setVisibility(View.GONE);
944 // Open the display images spinner when the TextView is clicked.
945 displayImagesTextView.setOnClickListener((View v) -> {
946 // Open the user agent spinner.
947 displayWebpageImagesSpinner.performClick();
950 // Set the pinned SSL certificate icon.
951 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.
953 pinnedSslCertificateSwitch.setChecked(true);
955 // Set the icon according to the theme.
957 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_dark));
959 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_light));
961 } else { // Pinned SSL certificate is disabled.
962 // Uncheck the switch.
963 pinnedSslCertificateSwitch.setChecked(false);
965 // Set the icon according to the theme.
967 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_dark));
969 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_light));
973 // Store the current date.
974 Date currentDate = Calendar.getInstance().getTime();
976 // Setup the string builders to display the general certificate information in blue. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
977 savedSslCertificateIssuedToONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), savedSslCertificateIssuedToONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
978 savedSslCertificateIssuedToUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), savedSslCertificateIssuedToUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
979 savedSslCertificateIssuedByCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), savedSslCertificateIssuedByCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
980 savedSslCertificateIssuedByONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), savedSslCertificateIssuedByONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
981 savedSslCertificateIssuedByUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), savedSslCertificateIssuedByUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
983 // Check the certificate Common Name against the domain name.
984 boolean savedSSlCertificateCommonNameMatchesDomainName = checkDomainNameAgainstCertificate(domainNameString, savedSslCertificateIssuedToCNameString);
986 // Format the issued to Common Name color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
987 if (savedSSlCertificateCommonNameMatchesDomainName) {
988 savedSslCertificateIssuedToCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), savedSslCertificateIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
990 savedSslCertificateIssuedToCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), savedSslCertificateIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
993 // Format the start date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
994 if ((savedSslCertificateStartDate != null) && savedSslCertificateStartDate.after(currentDate)) { // The certificate start date is in the future.
995 savedSslCertificateStartDateStringBuilder.setSpan(redColorSpan, startDateLabel.length(), savedSslCertificateStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
996 } else { // The certificate start date is in the past.
997 savedSslCertificateStartDateStringBuilder.setSpan(blueColorSpan, startDateLabel.length(), savedSslCertificateStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1000 // Format the end date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
1001 if ((savedSslCertificateEndDate != null) && savedSslCertificateEndDate.before(currentDate)) { // The certificate end date is in the past.
1002 savedSslCertificateEndDateStringBuilder.setSpan(redColorSpan, endDateLabel.length(), savedSslCertificateEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1003 } else { // The certificate end date is in the future.
1004 savedSslCertificateEndDateStringBuilder.setSpan(blueColorSpan, endDateLabel.length(), savedSslCertificateEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1007 // Display the saved website SSL certificate strings.
1008 savedSslCertificateIssuedToCNameTextView.setText(savedSslCertificateIssuedToCNameStringBuilder);
1009 savedSslCertificateIssuedToONameTextView.setText(savedSslCertificateIssuedToONameStringBuilder);
1010 savedSslCertificateIssuedToUNameTextView.setText(savedSslCertificateIssuedToUNameStringBuilder);
1011 savedSslCertificateIssuedByCNameTextView.setText(savedSslCertificateIssuedByCNameStringBuilder);
1012 savedSslCertificateIssuedByONameTextView.setText(savedSslCertificateIssuedByONameStringBuilder);
1013 savedSslCertificateIssuedByUNameTextView.setText(savedSslCertificateIssuedByUNameStringBuilder);
1014 savedSslCertificateStartDateTextView.setText(savedSslCertificateStartDateStringBuilder);
1015 savedSslCertificateEndDateTextView.setText(savedSslCertificateEndDateStringBuilder);
1017 // Populate the current website SSL certificate if there is one.
1018 if (currentWebsiteSslCertificate != null) {
1019 // Get the strings from the SSL certificate.
1020 String currentWebsiteCertificateIssuedToCNameString = currentWebsiteSslCertificate.getIssuedTo().getCName();
1021 String currentWebsiteCertificateIssuedToONameString = currentWebsiteSslCertificate.getIssuedTo().getOName();
1022 String currentWebsiteCertificateIssuedToUNameString = currentWebsiteSslCertificate.getIssuedTo().getUName();
1023 String currentWebsiteCertificateIssuedByCNameString = currentWebsiteSslCertificate.getIssuedBy().getCName();
1024 String currentWebsiteCertificateIssuedByONameString = currentWebsiteSslCertificate.getIssuedBy().getOName();
1025 String currentWebsiteCertificateIssuedByUNameString = currentWebsiteSslCertificate.getIssuedBy().getUName();
1026 Date currentWebsiteCertificateStartDate = currentWebsiteSslCertificate.getValidNotBeforeDate();
1027 Date currentWebsiteCertificateEndDate = currentWebsiteSslCertificate.getValidNotAfterDate();
1029 // Create a spannable string builder for each text view that needs multiple colors of text.
1030 SpannableStringBuilder currentWebsiteCertificateIssuedToCNameStringBuilder = new SpannableStringBuilder(cNameLabel + currentWebsiteCertificateIssuedToCNameString);
1031 SpannableStringBuilder currentWebsiteCertificateIssuedToONameStringBuilder = new SpannableStringBuilder(oNameLabel + currentWebsiteCertificateIssuedToONameString);
1032 SpannableStringBuilder currentWebsiteCertificateIssuedToUNameStringBuilder = new SpannableStringBuilder(uNameLabel + currentWebsiteCertificateIssuedToUNameString);
1033 SpannableStringBuilder currentWebsiteCertificateIssuedByCNameStringBuilder = new SpannableStringBuilder(cNameLabel + currentWebsiteCertificateIssuedByCNameString);
1034 SpannableStringBuilder currentWebsiteCertificateIssuedByONameStringBuilder = new SpannableStringBuilder(oNameLabel + currentWebsiteCertificateIssuedByONameString);
1035 SpannableStringBuilder currentWebsiteCertificateIssuedByUNameStringBuilder = new SpannableStringBuilder(uNameLabel + currentWebsiteCertificateIssuedByUNameString);
1036 SpannableStringBuilder currentWebsiteCertificateStartDateStringBuilder = new SpannableStringBuilder(startDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG)
1037 .format(currentWebsiteCertificateStartDate));
1038 SpannableStringBuilder currentWebsiteCertificateEndDateStringBuilder = new SpannableStringBuilder(endDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG)
1039 .format(currentWebsiteCertificateEndDate));
1041 // Setup the string builders to display the general certificate information in blue. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
1042 currentWebsiteCertificateIssuedToONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), currentWebsiteCertificateIssuedToONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1043 currentWebsiteCertificateIssuedToUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), currentWebsiteCertificateIssuedToUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1044 currentWebsiteCertificateIssuedByCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), currentWebsiteCertificateIssuedByCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1045 currentWebsiteCertificateIssuedByONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), currentWebsiteCertificateIssuedByONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1046 currentWebsiteCertificateIssuedByUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), currentWebsiteCertificateIssuedByUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1048 // Check the certificate Common Name against the domain name.
1049 boolean currentWebsiteCertificateCommonNameMatchesDomainName = checkDomainNameAgainstCertificate(domainNameString, currentWebsiteCertificateIssuedToCNameString);
1051 // Format the issued to Common Name color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
1052 if (currentWebsiteCertificateCommonNameMatchesDomainName) {
1053 currentWebsiteCertificateIssuedToCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), currentWebsiteCertificateIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1055 currentWebsiteCertificateIssuedToCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), currentWebsiteCertificateIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1058 // Format the start date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
1059 if (currentWebsiteCertificateStartDate.after(currentDate)) { // The certificate start date is in the future.
1060 currentWebsiteCertificateStartDateStringBuilder.setSpan(redColorSpan, startDateLabel.length(), currentWebsiteCertificateStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1061 } else { // The certificate start date is in the past.
1062 currentWebsiteCertificateStartDateStringBuilder.setSpan(blueColorSpan, startDateLabel.length(), currentWebsiteCertificateStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1065 // Format the end date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
1066 if (currentWebsiteCertificateEndDate.before(currentDate)) { // The certificate end date is in the past.
1067 currentWebsiteCertificateEndDateStringBuilder.setSpan(redColorSpan, endDateLabel.length(), currentWebsiteCertificateEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1068 } else { // The certificate end date is in the future.
1069 currentWebsiteCertificateEndDateStringBuilder.setSpan(blueColorSpan, endDateLabel.length(), currentWebsiteCertificateEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1072 // Display the current website SSL certificate strings.
1073 currentWebsiteCertificateIssuedToCNameTextView.setText(currentWebsiteCertificateIssuedToCNameStringBuilder);
1074 currentWebsiteCertificateIssuedToONameTextView.setText(currentWebsiteCertificateIssuedToONameStringBuilder);
1075 currentWebsiteCertificateIssuedToUNameTextView.setText(currentWebsiteCertificateIssuedToUNameStringBuilder);
1076 currentWebsiteCertificateIssuedByCNameTextView.setText(currentWebsiteCertificateIssuedByCNameStringBuilder);
1077 currentWebsiteCertificateIssuedByONameTextView.setText(currentWebsiteCertificateIssuedByONameStringBuilder);
1078 currentWebsiteCertificateIssuedByUNameTextView.setText(currentWebsiteCertificateIssuedByUNameStringBuilder);
1079 currentWebsiteCertificateStartDateTextView.setText(currentWebsiteCertificateStartDateStringBuilder);
1080 currentWebsiteCertificateEndDateTextView.setText(currentWebsiteCertificateEndDateStringBuilder);
1083 // Set the initial display status of the SSL certificates card views.
1084 if (pinnedSslCertificateSwitch.isChecked()) { // An SSL certificate is pinned.
1085 // Set the visibility of the saved SSL certificate.
1086 if (savedSslCertificateIssuedToCNameString == null) {
1087 savedSslCertificateCardView.setVisibility(View.GONE);
1089 savedSslCertificateCardView.setVisibility(View.VISIBLE);
1092 // Set the visibility of the current website SSL certificate.
1093 if (currentWebsiteSslCertificate == null) { // There is no current SSL certificate.
1094 // Hide the SSL certificate.
1095 currentWebsiteCertificateCardView.setVisibility(View.GONE);
1097 // Show the instruction.
1098 noCurrentWebsiteCertificateTextView.setVisibility(View.VISIBLE);
1099 } else { // There is a current SSL certificate.
1100 // Show the SSL certificate.
1101 currentWebsiteCertificateCardView.setVisibility(View.VISIBLE);
1103 // Hide the instruction.
1104 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
1107 // Set the status of the radio buttons and the card view backgrounds.
1108 if (savedSslCertificateCardView.getVisibility() == View.VISIBLE) { // The saved SSL certificate is displayed.
1109 // Check the saved SSL certificate radio button.
1110 savedSslCertificateRadioButton.setChecked(true);
1112 // Uncheck the current website SSL certificate radio button.
1113 currentWebsiteCertificateRadioButton.setChecked(false);
1115 // Darken the background of the current website SSL certificate linear layout according to the theme.
1117 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1119 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1121 } else if (currentWebsiteCertificateCardView.getVisibility() == View.VISIBLE) { // The saved SSL certificate is hidden but the current website SSL certificate is visible.
1122 // Check the current website SSL certificate radio button.
1123 currentWebsiteCertificateRadioButton.setChecked(true);
1125 // Uncheck the saved SSL certificate radio button.
1126 savedSslCertificateRadioButton.setChecked(false);
1127 } else { // Neither SSL certificate is visible.
1128 // Uncheck both radio buttons.
1129 savedSslCertificateRadioButton.setChecked(false);
1130 currentWebsiteCertificateRadioButton.setChecked(false);
1132 } else { // An SSL certificate is not pinned.
1133 // Hide the SSl certificates and instructions.
1134 savedSslCertificateCardView.setVisibility(View.GONE);
1135 currentWebsiteCertificateCardView.setVisibility(View.GONE);
1136 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
1138 // Uncheck the radio buttons.
1139 savedSslCertificateRadioButton.setChecked(false);
1140 currentWebsiteCertificateRadioButton.setChecked(false);
1143 // Set the pinned IP addresses icon.
1144 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.
1145 // Check the switch.
1146 pinnedIpAddressesSwitch.setChecked(true);
1148 // Set the icon according to the theme.
1150 pinnedIpAddressesImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_dark));
1152 pinnedIpAddressesImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_light));
1154 } else { // Pinned IP Addresses is disabled.
1155 // Uncheck the switch.
1156 pinnedIpAddressesSwitch.setChecked(false);
1158 // Set the icon according to the theme.
1160 pinnedIpAddressesImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_dark));
1162 pinnedIpAddressesImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_light));
1166 // Populate the saved and current IP addresses.
1167 savedIpAddressesTextView.setText(savedIpAddresses);
1168 currentIpAddressesTextView.setText(DomainsActivity.currentIpAddresses);
1170 // Set the initial display status of the IP addresses card views.
1171 if (pinnedIpAddressesSwitch.isChecked()) { // IP addresses are pinned.
1172 // Set the visibility of the saved IP addresses.
1173 if (savedIpAddresses == null) { // There are no saved IP addresses.
1174 savedIpAddressesCardView.setVisibility(View.GONE);
1175 } else { // There are saved IP addresses.
1176 savedIpAddressesCardView.setVisibility(View.VISIBLE);
1179 // Set the visibility of the current IP addresses.
1180 currentIpAddressesCardView.setVisibility(View.VISIBLE);
1182 // Set the status of the radio buttons and the card view backgrounds.
1183 if (savedIpAddressesCardView.getVisibility() == View.VISIBLE) { // The saved IP addresses are displayed.
1184 // Check the saved IP addresses radio button.
1185 savedIpAddressesRadioButton.setChecked(true);
1187 // Uncheck the current IP addresses radio button.
1188 currentIpAddressesRadioButton.setChecked(false);
1190 // Darken the background of the current IP addresses linear layout according to the theme.
1192 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1194 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1196 } else { // The saved IP addresses are hidden.
1197 // Check the current IP addresses radio button.
1198 currentIpAddressesRadioButton.setChecked(true);
1200 // Uncheck the saved IP addresses radio button.
1201 savedIpAddressesRadioButton.setChecked(false);
1203 } else { // IP addresses are not pinned.
1204 // Hide the IP addresses card views.
1205 savedIpAddressesCardView.setVisibility(View.GONE);
1206 currentIpAddressesCardView.setVisibility(View.GONE);
1208 // Uncheck the radio buttons.
1209 savedIpAddressesRadioButton.setChecked(false);
1210 currentIpAddressesRadioButton.setChecked(false);
1214 // Set the JavaScript switch listener.
1215 javaScriptEnabledSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1216 if (isChecked) { // JavaScript is enabled.
1217 // Update the JavaScript icon.
1218 javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.javascript_enabled));
1220 // Enable the DOM storage `Switch`.
1221 domStorageEnabledSwitch.setEnabled(true);
1223 // Update the DOM storage icon.
1224 if (domStorageEnabledSwitch.isChecked()) { // DOM storage is enabled.
1225 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_enabled));
1226 } else { // DOM storage is disabled.
1227 // Set the icon according to the theme.
1229 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_dark));
1231 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_light));
1234 } else { // JavaScript is disabled.
1235 // Update the JavaScript icon.
1236 javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.privacy_mode));
1238 // Disable the DOM storage `Switch`.
1239 domStorageEnabledSwitch.setEnabled(false);
1241 // Set the DOM storage icon according to the theme.
1243 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_dark));
1245 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_light));
1250 // Set the first-party cookies switch listener.
1251 firstPartyCookiesEnabledSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1252 if (isChecked) { // First-party cookies are enabled.
1253 // Update the first-party cookies icon.
1254 firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_enabled));
1256 // Enable the third-party cookies switch.
1257 thirdPartyCookiesEnabledSwitch.setEnabled(true);
1259 // Update the third-party cookies icon.
1260 if (thirdPartyCookiesEnabledSwitch.isChecked()) { // Third-party cookies are enabled.
1261 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_warning));
1262 } else { // Third-party cookies are disabled.
1263 // Set the third-party cookies icon according to the theme.
1265 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_dark));
1267 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_light));
1270 } else { // First-party cookies are disabled.
1271 // Update the first-party cookies icon according to the theme.
1273 firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_dark));
1275 firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_light));
1278 // Disable the third-party cookies switch.
1279 thirdPartyCookiesEnabledSwitch.setEnabled(false);
1281 // Set the third-party cookies icon according to the theme.
1283 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_ghosted_dark));
1285 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_ghosted_light));
1290 // Set the third-party cookies switch listener.
1291 thirdPartyCookiesEnabledSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1294 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_warning));
1296 // Update the third-party cookies icon according to the theme.
1298 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_dark));
1300 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_light));
1305 // Set the DOM Storage switch listener.
1306 domStorageEnabledSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1309 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_enabled));
1311 // Set the icon according to the theme.
1313 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_dark));
1315 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_light));
1320 // Set the form data switch listener. It can be removed once the minimum API >= 26.
1321 if (Build.VERSION.SDK_INT < 26) {
1322 formDataEnabledSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1325 formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_enabled));
1327 // Set the icon according to the theme.
1329 formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_disabled_dark));
1331 formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_disabled_light));
1337 // Set the EasyList switch listener.
1338 easyListSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1340 if (isChecked) { // EasyList is on.
1341 // Set the icon according to the theme.
1343 easyListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_enabled_dark));
1345 easyListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_enabled_light));
1347 } else { // EasyList is off.
1348 // Set the icon according to the theme.
1350 easyListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_disabled_dark));
1352 easyListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_disabled_light));
1357 // Set the EasyPrivacy switch listener.
1358 easyPrivacySwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1360 if (isChecked) { // EasyPrivacy is on.
1361 // Set the icon according to the theme.
1363 easyPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_enabled_dark));
1365 easyPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_enabled_light));
1367 } else { // EasyPrivacy is off.
1368 // Set the icon according to the theme.
1370 easyPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_disabled_dark));
1372 easyPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_disabled_light));
1377 // Set the Fanboy's Annoyance List switch listener.
1378 fanboysAnnoyanceListSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1379 // Update the icon and Fanboy's Social Blocking List.
1380 if (isChecked) { // Fanboy's Annoyance List is on.
1381 // Set the icon according to the theme.
1383 fanboysAnnoyanceListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_dark));
1385 fanboysAnnoyanceListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_light));
1388 // Disable the Fanboy's Social Blocking List switch.
1389 fanboysSocialBlockingListSwitch.setEnabled(false);
1391 // Update the Fanboy's Social Blocking List icon according to the theme.
1393 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_ghosted_dark));
1395 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_ghosted_light));
1397 } else { // Fanboy's Annoyance List is off.
1398 // Set the icon according to the theme.
1400 fanboysAnnoyanceListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_dark));
1402 fanboysAnnoyanceListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_light));
1405 // Enable the Fanboy's Social Blocking List switch.
1406 fanboysSocialBlockingListSwitch.setEnabled(true);
1408 // Update the Fanboy's Social Blocking List icon.
1409 if (fanboysSocialBlockingListSwitch.isChecked()) { // Fanboy's Social Blocking List is on.
1410 // Update the icon according to the theme.
1412 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_dark));
1414 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_light));
1416 } else { // Fanboy's Social Blocking List is off.
1417 // Update the icon according to the theme.
1419 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_dark));
1421 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_light));
1428 // Set the Fanboy's Social Blocking List switch listener.
1429 fanboysSocialBlockingListSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1431 if (isChecked) { // Fanboy's Social Blocking List is on.
1432 // Set the icon according to the theme.
1434 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_dark));
1436 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_light));
1438 } else { // Fanboy's Social Blocking List is off.
1439 // Set the icon according to the theme.
1441 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_dark));
1443 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_light));
1448 // Set the UltraPrivacy switch listener.
1449 ultraPrivacySwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1451 if (isChecked) { // UltraPrivacy is on.
1452 // Set the icon according to the theme.
1454 ultraPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_enabled_dark));
1456 ultraPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_enabled_light));
1458 } else { // UltraPrivacy is off.
1459 // Set the icon according to the theme.
1461 ultraPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_disabled_dark));
1463 ultraPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_disabled_light));
1468 // Set the block all third-party requests switch listener.
1469 blockAllThirdPartyRequestsSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1471 if (isChecked) { // Blocking all third-party requests is on.
1472 // Set the icon according to the theme.
1474 blockAllThirdPartyRequestsImageView.setImageDrawable(resources.getDrawable(R.drawable.block_all_third_party_requests_enabled_dark));
1476 blockAllThirdPartyRequestsImageView.setImageDrawable(resources.getDrawable(R.drawable.block_all_third_party_requests_enabled_light));
1478 } else { // Blocking all third-party requests is off.
1479 // Set the icon according to the theme.
1481 blockAllThirdPartyRequestsImageView.setImageDrawable(resources.getDrawable(R.drawable.block_all_third_party_requests_disabled_dark));
1483 blockAllThirdPartyRequestsImageView.setImageDrawable(resources.getDrawable(R.drawable.block_all_third_party_requests_disabled_light));
1488 // Set the user agent spinner listener.
1489 userAgentSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1491 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1492 // Set the new user agent.
1494 case MainWebViewActivity.DOMAINS_SYSTEM_DEFAULT_USER_AGENT:
1495 // Show the user agent TextView.
1496 userAgentTextView.setVisibility(View.VISIBLE);
1498 // Hide the custom user agent EditText.
1499 customUserAgentEditText.setVisibility(View.GONE);
1501 // Set the user text.
1502 switch (defaultUserAgentArrayPosition) {
1503 case MainWebViewActivity.UNRECOGNIZED_USER_AGENT: // The default user agent name is not on the canonical list.
1504 // This is probably because it was set in an older version of Privacy Browser before the switch to persistent user agent names.
1505 userAgentTextView.setText(defaultUserAgentName);
1508 case MainWebViewActivity.SETTINGS_WEBVIEW_DEFAULT_USER_AGENT:
1509 // Display the `WebView` default user agent.
1510 userAgentTextView.setText(webViewDefaultUserAgentString);
1513 case MainWebViewActivity.SETTINGS_CUSTOM_USER_AGENT:
1514 // Display the custom user agent.
1515 userAgentTextView.setText(defaultCustomUserAgentString);
1519 // Get the user agent string from the user agent data array.
1520 userAgentTextView.setText(userAgentDataArray[defaultUserAgentArrayPosition]);
1524 case MainWebViewActivity.DOMAINS_WEBVIEW_DEFAULT_USER_AGENT:
1525 // Show the user agent TextView and set the text.
1526 userAgentTextView.setVisibility(View.VISIBLE);
1527 userAgentTextView.setText(webViewDefaultUserAgentString);
1529 // Hide the custom user agent EditTex.
1530 customUserAgentEditText.setVisibility(View.GONE);
1533 case MainWebViewActivity.DOMAINS_CUSTOM_USER_AGENT:
1534 // Hide the user agent TextView.
1535 userAgentTextView.setVisibility(View.GONE);
1537 // Show the custom user agent EditText and set the current user agent name as the text.
1538 customUserAgentEditText.setVisibility(View.VISIBLE);
1539 customUserAgentEditText.setText(currentUserAgentName);
1543 // 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.
1544 userAgentTextView.setVisibility(View.VISIBLE);
1545 userAgentTextView.setText(userAgentDataArray[position - 1]);
1547 // Hide `customUserAgentEditText`.
1548 customUserAgentEditText.setVisibility(View.GONE);
1553 public void onNothingSelected(AdapterView<?> parent) {
1558 // Set the font size spinner listener.
1559 fontSizeSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1561 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1562 // Update the display options for `fontSizeTextView`.
1563 if (position == 0) { // System default font size has been selected. Display `fontSizeTextView`.
1564 fontSizeTextView.setVisibility(View.VISIBLE);
1565 } else { // A custom font size has been selected. Hide `fontSizeTextView`.
1566 fontSizeTextView.setVisibility(View.GONE);
1571 public void onNothingSelected(AdapterView<?> parent) {
1576 // Set the swipe to refresh spinner listener.
1577 swipeToRefreshSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1579 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1580 // 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.
1582 case DomainsDatabaseHelper.SWIPE_TO_REFRESH_SYSTEM_DEFAULT:
1583 if (defaultSwipeToRefresh) { // Swipe to refresh enabled by default.
1584 // Set the icon according to the theme.
1586 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_enabled_dark));
1588 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_enabled_light));
1590 } else { // Swipe to refresh disabled by default.
1591 // Set the icon according to the theme.
1593 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_disabled_dark));
1595 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_disabled_light));
1599 // Show the swipe to refresh TextView.
1600 swipeToRefreshTextView.setVisibility(View.VISIBLE);
1603 case DomainsDatabaseHelper.SWIPE_TO_REFRESH_ENABLED:
1604 // Set the icon according to the theme.
1606 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_enabled_dark));
1608 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_enabled_light));
1611 // Hide the swipe to refresh TextView.
1612 swipeToRefreshTextView.setVisibility(View.GONE);
1615 case DomainsDatabaseHelper.SWIPE_TO_REFRESH_DISABLED:
1616 // Set the icon according to the theme.
1618 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_disabled_dark));
1620 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_disabled_light));
1623 // Hide the swipe to refresh TextView.
1624 swipeToRefreshTextView.setVisibility(View.GONE);
1629 public void onNothingSelected(AdapterView<?> parent) {
1634 // Set the night mode spinner listener.
1635 nightModeSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1637 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1638 // 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.
1640 case DomainsDatabaseHelper.NIGHT_MODE_SYSTEM_DEFAULT:
1641 if (defaultNightMode) { // Night mode enabled by default.
1642 // Set the icon according to the theme.
1644 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_dark));
1646 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_light));
1648 } else { // Night mode disabled by default.
1649 // Set the icon according to the theme.
1651 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_dark));
1653 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_light));
1657 // Show the night mode TextView.
1658 nightModeTextView.setVisibility(View.VISIBLE);
1661 case DomainsDatabaseHelper.NIGHT_MODE_ENABLED:
1662 // Set the icon according to the theme.
1664 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_dark));
1666 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_light));
1669 // Hide `nightModeTextView`.
1670 nightModeTextView.setVisibility(View.GONE);
1673 case DomainsDatabaseHelper.NIGHT_MODE_DISABLED:
1674 // Set the icon according to the theme.
1676 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_dark));
1678 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_light));
1681 // Hide `nightModeTextView`.
1682 nightModeTextView.setVisibility(View.GONE);
1686 // Create a `boolean` to store the current night mode setting.
1687 boolean currentNightModeEnabled = (position == DomainsDatabaseHelper.NIGHT_MODE_ENABLED) || ((position == DomainsDatabaseHelper.NIGHT_MODE_SYSTEM_DEFAULT) && defaultNightMode);
1689 // Disable the JavaScript `Switch` if night mode is enabled.
1690 if (currentNightModeEnabled) {
1691 javaScriptEnabledSwitch.setEnabled(false);
1693 javaScriptEnabledSwitch.setEnabled(true);
1696 // Update the JavaScript icon.
1697 if ((javaScriptEnabledInt == 1) || currentNightModeEnabled) {
1698 javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.javascript_enabled));
1700 javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.privacy_mode));
1703 // Update the DOM storage status.
1704 if ((javaScriptEnabledInt == 1) || currentNightModeEnabled) { // JavaScript is enabled.
1705 // Enable the DOM storage `Switch`.
1706 domStorageEnabledSwitch.setEnabled(true);
1708 // Set the DOM storage status. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
1709 if (domStorageEnabledInt == 1) { // Both JavaScript and DOM storage are enabled.
1710 domStorageEnabledSwitch.setChecked(true);
1711 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_enabled));
1712 } else { // JavaScript is enabled but DOM storage is disabled.
1713 // Set the DOM storage switch to off.
1714 domStorageEnabledSwitch.setChecked(false);
1716 // Set the icon according to the theme.
1718 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_dark));
1720 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_light));
1723 } else { // JavaScript is disabled.
1724 // Disable the DOM storage `Switch`.
1725 domStorageEnabledSwitch.setEnabled(false);
1727 // Set the checked status of DOM storage.
1728 if (domStorageEnabledInt == 1) { // DOM storage is enabled but JavaScript is disabled.
1729 domStorageEnabledSwitch.setChecked(true);
1730 } else { // Both JavaScript and DOM storage are disabled.
1731 domStorageEnabledSwitch.setChecked(false);
1734 // Set the icon according to the theme.
1736 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_dark));
1738 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_light));
1744 public void onNothingSelected(AdapterView<?> parent) {
1749 // Set the display webpage images spinner listener.
1750 displayWebpageImagesSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1752 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1753 // Update the icon and the visibility of `displayImagesTextView`.
1755 case DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_SYSTEM_DEFAULT:
1756 if (defaultDisplayWebpageImages) {
1757 // Set the icon according to the theme.
1759 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_dark));
1761 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_light));
1764 // Set the icon according to the theme.
1766 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_dark));
1768 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_light));
1772 // Show `displayImagesTextView`.
1773 displayImagesTextView.setVisibility(View.VISIBLE);
1776 case DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_ENABLED:
1777 // Set the icon according to the theme.
1779 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_dark));
1781 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_light));
1784 // Hide `displayImagesTextView`.
1785 displayImagesTextView.setVisibility(View.GONE);
1788 case DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_DISABLED:
1789 // Set the icon according to the theme.
1791 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_dark));
1793 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_light));
1796 // Hide `displayImagesTextView`.
1797 displayImagesTextView.setVisibility(View.GONE);
1803 public void onNothingSelected(AdapterView<?> parent) {
1808 // Set the pinned SSL certificate switch listener.
1809 pinnedSslCertificateSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1811 if (isChecked) { // SSL certificate pinning is enabled.
1812 // Set the icon according to the theme.
1814 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_dark));
1816 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_light));
1819 // Update the visibility of the saved SSL certificate.
1820 if (savedSslCertificateIssuedToCNameString == null) {
1821 savedSslCertificateCardView.setVisibility(View.GONE);
1823 savedSslCertificateCardView.setVisibility(View.VISIBLE);
1826 // Update the visibility of the current website SSL certificate.
1827 if (currentWebsiteSslCertificate == null) {
1828 // Hide the SSL certificate.
1829 currentWebsiteCertificateCardView.setVisibility(View.GONE);
1831 // Show the instruction.
1832 noCurrentWebsiteCertificateTextView.setVisibility(View.VISIBLE);
1834 // Show the SSL certificate.
1835 currentWebsiteCertificateCardView.setVisibility(View.VISIBLE);
1837 // Hide the instruction.
1838 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
1841 // Set the status of the radio buttons.
1842 if (savedSslCertificateCardView.getVisibility() == View.VISIBLE) { // The saved SSL certificate is displayed.
1843 // Check the saved SSL certificate radio button.
1844 savedSslCertificateRadioButton.setChecked(true);
1846 // Uncheck the current website SSL certificate radio button.
1847 currentWebsiteCertificateRadioButton.setChecked(false);
1849 // Set the background of the saved SSL certificate linear layout to be transparent.
1850 savedSslCertificateLinearLayout.setBackgroundResource(R.color.transparent);
1852 // Darken the background of the current website SSL certificate linear layout according to the theme.
1854 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1856 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1859 // Scroll to the current website SSL certificate card.
1860 savedSslCertificateCardView.getParent().requestChildFocus(savedSslCertificateCardView, savedSslCertificateCardView);
1861 } else if (currentWebsiteCertificateCardView.getVisibility() == View.VISIBLE) { // The saved SSL certificate is hidden but the current website SSL certificate is visible.
1862 // Check the current website SSL certificate radio button.
1863 currentWebsiteCertificateRadioButton.setChecked(true);
1865 // Uncheck the saved SSL certificate radio button.
1866 savedSslCertificateRadioButton.setChecked(false);
1868 // Set the background of the current website SSL certificate linear layout to be transparent.
1869 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.transparent);
1871 // Darken the background of the saved SSL certificate linear layout according to the theme.
1873 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1875 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1878 // Scroll to the current website SSL certificate card.
1879 currentWebsiteCertificateCardView.getParent().requestChildFocus(currentWebsiteCertificateCardView, currentWebsiteCertificateCardView);
1880 } else { // Neither SSL certificate is visible.
1881 // Uncheck both radio buttons.
1882 savedSslCertificateRadioButton.setChecked(false);
1883 currentWebsiteCertificateRadioButton.setChecked(false);
1885 // Scroll to the current website SSL certificate card.
1886 noCurrentWebsiteCertificateTextView.getParent().requestChildFocus(noCurrentWebsiteCertificateTextView, noCurrentWebsiteCertificateTextView);
1888 } else { // SSL certificate pinning is disabled.
1889 // Set the icon according to the theme.
1891 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_dark));
1893 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_light));
1896 // Hide the SSl certificates and instructions.
1897 savedSslCertificateCardView.setVisibility(View.GONE);
1898 currentWebsiteCertificateCardView.setVisibility(View.GONE);
1899 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
1901 // Uncheck the radio buttons.
1902 savedSslCertificateRadioButton.setChecked(false);
1903 currentWebsiteCertificateRadioButton.setChecked(false);
1907 savedSslCertificateCardView.setOnClickListener((View view) -> {
1908 // Check the saved SSL certificate radio button.
1909 savedSslCertificateRadioButton.setChecked(true);
1911 // Uncheck the current website SSL certificate radio button.
1912 currentWebsiteCertificateRadioButton.setChecked(false);
1914 // Set the background of the saved SSL certificate linear layout to be transparent.
1915 savedSslCertificateLinearLayout.setBackgroundResource(R.color.transparent);
1917 // Darken the background of the current website SSL certificate linear layout according to the theme.
1919 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1921 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1925 savedSslCertificateRadioButton.setOnClickListener((View view) -> {
1926 // Check the saved SSL certificate radio button.
1927 savedSslCertificateRadioButton.setChecked(true);
1929 // Uncheck the current website SSL certificate radio button.
1930 currentWebsiteCertificateRadioButton.setChecked(false);
1932 // Set the background of the saved SSL certificate linear layout to be transparent.
1933 savedSslCertificateLinearLayout.setBackgroundResource(R.color.transparent);
1935 // Darken the background of the current website SSL certificate linear layout according to the theme.
1937 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1939 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1943 currentWebsiteCertificateCardView.setOnClickListener((View view) -> {
1944 // Check the current website SSL certificate radio button.
1945 currentWebsiteCertificateRadioButton.setChecked(true);
1947 // Uncheck the saved SSL certificate radio button.
1948 savedSslCertificateRadioButton.setChecked(false);
1950 // Set the background of the current website SSL certificate linear layout to be transparent.
1951 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.transparent);
1953 // Darken the background of the saved SSL certificate linear layout according to the theme.
1955 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1957 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1961 currentWebsiteCertificateRadioButton.setOnClickListener((View view) -> {
1962 // Check the current website SSL certificate radio button.
1963 currentWebsiteCertificateRadioButton.setChecked(true);
1965 // Uncheck the saved SSL certificate radio button.
1966 savedSslCertificateRadioButton.setChecked(false);
1968 // Set the background of the current website SSL certificate linear layout to be transparent.
1969 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.transparent);
1971 // Darken the background of the saved SSL certificate linear layout according to the theme.
1973 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1975 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1979 // Set the pinned IP addresses switch listener.
1980 pinnedIpAddressesSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1982 if (isChecked) { // IP addresses pinning is enabled.
1983 // Set the icon according to the theme.
1985 pinnedIpAddressesImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_dark));
1987 pinnedIpAddressesImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_light));
1990 // Update the visibility of the saved IP addresses card view.
1991 if (savedIpAddresses == null) { // There are no saved IP addresses.
1992 savedIpAddressesCardView.setVisibility(View.GONE);
1993 } else { // There are saved IP addresses.
1994 savedIpAddressesCardView.setVisibility(View.VISIBLE);
1997 // Show the current IP addresses card view.
1998 currentIpAddressesCardView.setVisibility(View.VISIBLE);
2000 // Set the status of the radio buttons.
2001 if (savedIpAddressesCardView.getVisibility() == View.VISIBLE) { // The saved IP addresses are visible.
2002 // Check the saved IP addresses radio button.
2003 savedIpAddressesRadioButton.setChecked(true);
2005 // Uncheck the current IP addresses radio button.
2006 currentIpAddressesRadioButton.setChecked(false);
2008 // Set the background of the saved IP addresses linear layout to be transparent.
2009 savedSslCertificateLinearLayout.setBackgroundResource(R.color.transparent);
2011 // Darken the background of the current IP addresses linear layout according to the theme.
2013 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2015 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2017 } else { // The saved IP addresses are not visible.
2018 // Check the current IP addresses radio button.
2019 currentIpAddressesRadioButton.setChecked(true);
2021 // Uncheck the saved IP addresses radio button.
2022 savedIpAddressesRadioButton.setChecked(false);
2024 // Set the background of the current IP addresses linear layout to be transparent.
2025 currentIpAddressesLinearLayout.setBackgroundResource(R.color.transparent);
2027 // Darken the background of the saved IP addresses linear layout according to the theme.
2029 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2031 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2035 // Scroll to the bottom of the card views.
2036 currentIpAddressesCardView.getParent().requestChildFocus(currentIpAddressesCardView, currentIpAddressesCardView);
2037 } else { // IP addresses pinning is disabled.
2038 // Set the icon according to the theme.
2040 pinnedIpAddressesImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_dark));
2042 pinnedIpAddressesImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_light));
2045 // Hide the IP addresses card views.
2046 savedIpAddressesCardView.setVisibility(View.GONE);
2047 currentIpAddressesCardView.setVisibility(View.GONE);
2049 // Uncheck the radio buttons.
2050 savedIpAddressesRadioButton.setChecked(false);
2051 currentIpAddressesRadioButton.setChecked(false);
2055 savedIpAddressesCardView.setOnClickListener((View view) -> {
2056 // Check the saved IP addresses radio button.
2057 savedIpAddressesRadioButton.setChecked(true);
2059 // Uncheck the current website IP addresses radio button.
2060 currentIpAddressesRadioButton.setChecked(false);
2062 // Set the background of the saved IP addresses linear layout to be transparent.
2063 savedIpAddressesLinearLayout.setBackgroundResource(R.color.transparent);
2065 // Darken the background of the current IP addresses linear layout according to the theme.
2067 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2069 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2073 savedIpAddressesRadioButton.setOnClickListener((View view) -> {
2074 // Check the saved IP addresses radio button.
2075 savedIpAddressesRadioButton.setChecked(true);
2077 // Uncheck the current website IP addresses radio button.
2078 currentIpAddressesRadioButton.setChecked(false);
2080 // Set the background of the saved IP addresses linear layout to be transparent.
2081 savedIpAddressesLinearLayout.setBackgroundResource(R.color.transparent);
2083 // Darken the background of the current IP addresses linear layout according to the theme.
2085 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2087 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2091 currentIpAddressesCardView.setOnClickListener((View view) -> {
2092 // Check the current IP addresses radio button.
2093 currentIpAddressesRadioButton.setChecked(true);
2095 // Uncheck the saved IP addresses radio button.
2096 savedIpAddressesRadioButton.setChecked(false);
2098 // Set the background of the current IP addresses linear layout to be transparent.
2099 currentIpAddressesLinearLayout.setBackgroundResource(R.color.transparent);
2101 // Darken the background of the saved IP addresses linear layout according to the theme.
2103 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2105 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2109 currentIpAddressesRadioButton.setOnClickListener((View view) -> {
2110 // Check the current IP addresses radio button.
2111 currentIpAddressesRadioButton.setChecked(true);
2113 // Uncheck the saved IP addresses radio button.
2114 savedIpAddressesRadioButton.setChecked(false);
2116 // Set the background of the current IP addresses linear layout to be transparent.
2117 currentIpAddressesLinearLayout.setBackgroundResource(R.color.transparent);
2119 // Darken the background of the saved IP addresses linear layout according to the theme.
2121 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2123 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2127 return domainSettingsView;
2130 private boolean checkDomainNameAgainstCertificate(String domainName, String certificateCommonName) {
2131 // Initialize `domainNamesMatch`.
2132 boolean domainNamesMatch = false;
2134 // Check various wildcard permutations if `domainName` and `certificateCommonName` are not empty.
2135 // `noinspection ConstantCondition` removes Android Studio's incorrect lint warning that `domainName` can never be `null`.
2136 //noinspection ConstantConditions
2137 if ((domainName != null) && (certificateCommonName != null)) {
2138 // Check if the domains match.
2139 if (domainName.equals(certificateCommonName)) {
2140 domainNamesMatch = true;
2143 // If `domainName` starts with a wildcard, check the base domain against all the subdomains of `certificateCommonName`.
2144 if (!domainNamesMatch && domainName.startsWith("*.") && (domainName.length() > 2)) {
2145 // Remove the initial `*.`.
2146 String baseDomainName = domainName.substring(2);
2148 // Setup a copy of `certificateCommonName` to test subdomains.
2149 String certificateCommonNameSubdomain = certificateCommonName;
2151 // Check all the subdomains in `certificateCommonNameSubdomain` against `baseDomainName`.
2152 while (!domainNamesMatch && certificateCommonNameSubdomain.contains(".")) { // Stop checking if we know that `domainNamesMatch` is `true` or if we run out of `.`.
2153 // Test the `certificateCommonNameSubdomain` against `baseDomainName`.
2154 if (certificateCommonNameSubdomain.equals(baseDomainName)) {
2155 domainNamesMatch = true;
2158 // Strip out the lowest subdomain of `certificateCommonNameSubdomain`.
2160 certificateCommonNameSubdomain = certificateCommonNameSubdomain.substring(certificateCommonNameSubdomain.indexOf(".") + 1);
2161 } catch (IndexOutOfBoundsException e) { // `certificateCommonNameSubdomain` ends with `.`.
2162 certificateCommonNameSubdomain = "";
2167 // If `certificateCommonName` starts with a wildcard, check the base common name against all the subdomains of `domainName`.
2168 if (!domainNamesMatch && certificateCommonName.startsWith("*.") && (certificateCommonName.length() > 2)) {
2169 // Remove the initial `*.`.
2170 String baseCertificateCommonName = certificateCommonName.substring(2);
2172 // Setup a copy of `domainName` to test subdomains.
2173 String domainNameSubdomain = domainName;
2175 // Check all the subdomains in `domainNameSubdomain` against `baseCertificateCommonName`.
2176 while (!domainNamesMatch && domainNameSubdomain.contains(".") && (domainNameSubdomain.length() > 2)) {
2177 // Test the `domainNameSubdomain` against `baseCertificateCommonName`.
2178 if (domainNameSubdomain.equals(baseCertificateCommonName)) {
2179 domainNamesMatch = true;
2182 // Strip out the lowest subdomain of `domainNameSubdomain`.
2184 domainNameSubdomain = domainNameSubdomain.substring(domainNameSubdomain.indexOf(".") + 1);
2185 } catch (IndexOutOfBoundsException e) { // `domainNameSubdomain` ends with `.`.
2186 domainNameSubdomain = "";
2191 // If both names start with a wildcard, check if the root of one contains the root of the other.
2192 if (!domainNamesMatch && domainName.startsWith("*.") && (domainName.length() > 2) && certificateCommonName.startsWith("*.") && (certificateCommonName.length() > 2)) {
2193 // Remove the wildcards.
2194 String rootDomainName = domainName.substring(2);
2195 String rootCertificateCommonName = certificateCommonName.substring(2);
2197 // Check if one name ends with the contents of the other. If so, there will be overlap in the their wildcard subdomains.
2198 if (rootDomainName.endsWith(rootCertificateCommonName) || rootCertificateCommonName.endsWith(rootDomainName)) {
2199 domainNamesMatch = true;
2204 return domainNamesMatch;