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.MainWebViewActivity;
57 import com.stoutner.privacybrowser.helpers.DomainsDatabaseHelper;
59 import java.text.DateFormat;
60 import java.util.Calendar;
61 import java.util.Date;
63 public class DomainSettingsFragment extends Fragment {
64 // `DATABASE_ID` is used by activities calling this fragment.
65 public static final String DATABASE_ID = "database_id";
67 // `databaseId` is public static so it can be accessed from `DomainsActivity`. It is also used in `onCreate()` and `onCreateView()`.
68 public static int databaseId;
71 public void onCreate(Bundle savedInstanceState) {
72 super.onCreate(savedInstanceState);
74 // Remove the lint warning that `getArguments` might be null.
75 assert getArguments() != null;
77 // Store the database id in `databaseId`.
78 databaseId = getArguments().getInt(DATABASE_ID);
81 // The deprecated `getDrawable()` must be used until the minimum API >= 21.
83 public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
84 // Inflate `domain_settings_fragment`. `false` does not attach it to the root `container`.
85 View domainSettingsView = inflater.inflate(R.layout.domain_settings_fragment, container, false);
87 // Get a handle for the context and the resources.
88 Context context = getContext();
89 final Resources resources = getResources();
91 // Get a handle for the shared preference.
92 SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
94 // Store the default settings.
95 final String defaultUserAgentName = sharedPreferences.getString("user_agent", getString(R.string.user_agent_default_value));
96 final String defaultCustomUserAgentString = sharedPreferences.getString("custom_user_agent", getString(R.string.custom_user_agent_default_value));
97 String defaultFontSizeString = sharedPreferences.getString("font_size", getString(R.string.font_size_default_value));
98 boolean defaultSwipeToRefresh = sharedPreferences.getBoolean("swipe_to_refresh", true);
99 final boolean defaultNightMode = sharedPreferences.getBoolean("night_mode", false);
100 final boolean defaultDisplayWebpageImages = sharedPreferences.getBoolean("display_webpage_images", true);
102 // Get handles for the views in the fragment.
103 final EditText domainNameEditText = domainSettingsView.findViewById(R.id.domain_settings_name_edittext);
104 final Switch javaScriptEnabledSwitch = domainSettingsView.findViewById(R.id.javascript_switch);
105 final ImageView javaScriptImageView = domainSettingsView.findViewById(R.id.javascript_imageview);
106 Switch firstPartyCookiesEnabledSwitch = domainSettingsView.findViewById(R.id.first_party_cookies_switch);
107 final ImageView firstPartyCookiesImageView = domainSettingsView.findViewById(R.id.first_party_cookies_imageview);
108 LinearLayout thirdPartyCookiesLinearLayout = domainSettingsView.findViewById(R.id.third_party_cookies_linearlayout);
109 final Switch thirdPartyCookiesEnabledSwitch = domainSettingsView.findViewById(R.id.third_party_cookies_switch);
110 final ImageView thirdPartyCookiesImageView = domainSettingsView.findViewById(R.id.third_party_cookies_imageview);
111 final Switch domStorageEnabledSwitch = domainSettingsView.findViewById(R.id.dom_storage_switch);
112 final ImageView domStorageImageView = domainSettingsView.findViewById(R.id.dom_storage_imageview);
113 Switch formDataEnabledSwitch = domainSettingsView.findViewById(R.id.form_data_switch); // The form data views can be remove once the minimum API >= 26.
114 final ImageView formDataImageView = domainSettingsView.findViewById(R.id.form_data_imageview); // The form data views can be remove once the minimum API >= 26.
115 Switch easyListSwitch = domainSettingsView.findViewById(R.id.easylist_switch);
116 ImageView easyListImageView = domainSettingsView.findViewById(R.id.easylist_imageview);
117 Switch easyPrivacySwitch = domainSettingsView.findViewById(R.id.easyprivacy_switch);
118 ImageView easyPrivacyImageView = domainSettingsView.findViewById(R.id.easyprivacy_imageview);
119 Switch fanboysAnnoyanceListSwitch = domainSettingsView.findViewById(R.id.fanboys_annoyance_list_switch);
120 ImageView fanboysAnnoyanceListImageView = domainSettingsView.findViewById(R.id.fanboys_annoyance_list_imageview);
121 Switch fanboysSocialBlockingListSwitch = domainSettingsView.findViewById(R.id.fanboys_social_blocking_list_switch);
122 ImageView fanboysSocialBlockingListImageView = domainSettingsView.findViewById(R.id.fanboys_social_blocking_list_imageview);
123 Switch ultraPrivacySwitch = domainSettingsView.findViewById(R.id.ultraprivacy_switch);
124 ImageView ultraPrivacyImageView = domainSettingsView.findViewById(R.id.ultraprivacy_imageview);
125 Switch blockAllThirdPartyRequestsSwitch = domainSettingsView.findViewById(R.id.block_all_third_party_requests_switch);
126 ImageView blockAllThirdPartyRequestsImageView = domainSettingsView.findViewById(R.id.block_all_third_party_requests_imageview);
127 final Spinner userAgentSpinner = domainSettingsView.findViewById(R.id.user_agent_spinner);
128 final TextView userAgentTextView = domainSettingsView.findViewById(R.id.user_agent_textview);
129 final EditText customUserAgentEditText = domainSettingsView.findViewById(R.id.custom_user_agent_edittext);
130 final Spinner fontSizeSpinner = domainSettingsView.findViewById(R.id.font_size_spinner);
131 final TextView fontSizeTextView = domainSettingsView.findViewById(R.id.font_size_textview);
132 final ImageView swipeToRefreshImageView = domainSettingsView.findViewById(R.id.swipe_to_refresh_imageview);
133 final Spinner swipeToRefreshSpinner = domainSettingsView.findViewById(R.id.swipe_to_refresh_spinner);
134 final TextView swipeToRefreshTextView = domainSettingsView.findViewById(R.id.swipe_to_refresh_textview);
135 final ImageView nightModeImageView = domainSettingsView.findViewById(R.id.night_mode_imageview);
136 final Spinner nightModeSpinner = domainSettingsView.findViewById(R.id.night_mode_spinner);
137 final TextView nightModeTextView = domainSettingsView.findViewById(R.id.night_mode_textview);
138 final ImageView displayWebpageImagesImageView = domainSettingsView.findViewById(R.id.display_webpage_images_imageview);
139 final Spinner displayWebpageImagesSpinner = domainSettingsView.findViewById(R.id.display_webpage_images_spinner);
140 final TextView displayImagesTextView = domainSettingsView.findViewById(R.id.display_webpage_images_textview);
141 final ImageView pinnedSslCertificateImageView = domainSettingsView.findViewById(R.id.pinned_ssl_certificate_imageview);
142 Switch pinnedSslCertificateSwitch = domainSettingsView.findViewById(R.id.pinned_ssl_certificate_switch);
143 final CardView savedSslCertificateCardView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_cardview);
144 LinearLayout savedSslCertificateLinearLayout = domainSettingsView.findViewById(R.id.saved_ssl_certificate_linearlayout);
145 final RadioButton savedSslCertificateRadioButton = domainSettingsView.findViewById(R.id.saved_ssl_certificate_radiobutton);
146 final TextView savedSslCertificateIssuedToCNameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_to_cname);
147 TextView savedSslCertificateIssuedToONameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_to_oname);
148 TextView savedSslCertificateIssuedToUNameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_to_uname);
149 TextView savedSslCertificateIssuedByCNameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_by_cname);
150 TextView savedSslCertificateIssuedByONameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_by_oname);
151 TextView savedSslCertificateIssuedByUNameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_by_uname);
152 TextView savedSslCertificateStartDateTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_start_date);
153 TextView savedSslCertificateEndDateTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_end_date);
154 final CardView currentWebsiteCertificateCardView = domainSettingsView.findViewById(R.id.current_website_certificate_cardview);
155 LinearLayout currentWebsiteCertificateLinearLayout = domainSettingsView.findViewById(R.id.current_website_certificate_linearlayout);
156 final RadioButton currentWebsiteCertificateRadioButton = domainSettingsView.findViewById(R.id.current_website_certificate_radiobutton);
157 final TextView currentWebsiteCertificateIssuedToCNameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_to_cname);
158 TextView currentWebsiteCertificateIssuedToONameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_to_oname);
159 TextView currentWebsiteCertificateIssuedToUNameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_to_uname);
160 TextView currentWebsiteCertificateIssuedByCNameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_by_cname);
161 TextView currentWebsiteCertificateIssuedByONameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_by_oname);
162 TextView currentWebsiteCertificateIssuedByUNameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_by_uname);
163 TextView currentWebsiteCertificateStartDateTextView = domainSettingsView.findViewById(R.id.current_website_certificate_start_date);
164 TextView currentWebsiteCertificateEndDateTextView = domainSettingsView.findViewById(R.id.current_website_certificate_end_date);
165 final TextView noCurrentWebsiteCertificateTextView = domainSettingsView.findViewById(R.id.no_current_website_certificate);
166 ImageView pinnedIpAddressesImageView = domainSettingsView.findViewById(R.id.pinned_ip_addresses_imageview);
167 Switch pinnedIpAddressesSwitch = domainSettingsView.findViewById(R.id.pinned_ip_addresses_switch);
168 CardView savedIpAddressesCardView = domainSettingsView.findViewById(R.id.saved_ip_addresses_cardview);
169 LinearLayout savedIpAddressesLinearLayout = domainSettingsView.findViewById(R.id.saved_ip_addresses_linearlayout);
170 RadioButton savedIpAddressesRadioButton = domainSettingsView.findViewById(R.id.saved_ip_addresses_radiobutton);
171 TextView savedIpAddressesTextView = domainSettingsView.findViewById(R.id.saved_ip_addresses_textview);
172 CardView currentIpAddressesCardView = domainSettingsView.findViewById(R.id.current_ip_addresses_cardview);
173 LinearLayout currentIpAddressesLinearLayout = domainSettingsView.findViewById(R.id.current_ip_addresses_linearlayout);
174 RadioButton currentIpAddressesRadioButton = domainSettingsView.findViewById(R.id.current_ip_addresses_radiobutton);
175 TextView currentIpAddressesTextView = domainSettingsView.findViewById(R.id.current_ip_addresses_textview);
177 // Setup the pinned labels.
178 String cNameLabel = getString(R.string.common_name) + " ";
179 String oNameLabel = getString(R.string.organization) + " ";
180 String uNameLabel = getString(R.string.organizational_unit) + " ";
181 String startDateLabel = getString(R.string.start_date) + " ";
182 String endDateLabel = getString(R.string.end_date) + " ";
184 // Get the current website SSL certificate
185 final SslCertificate currentWebsiteSslCertificate = MainWebViewActivity.sslCertificate;
187 // Initialize the database handler. The `0` specifies the database version, but that is ignored and set instead using a constant in `DomainsDatabaseHelper`.
188 DomainsDatabaseHelper domainsDatabaseHelper = new DomainsDatabaseHelper(context, null, null, 0);
190 // Get the database cursor for this ID and move it to the first row.
191 Cursor domainCursor = domainsDatabaseHelper.getCursorForId(databaseId);
192 domainCursor.moveToFirst();
194 // Save the cursor entries as variables.
195 String domainNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.DOMAIN_NAME));
196 final int javaScriptEnabledInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_JAVASCRIPT));
197 int firstPartyCookiesEnabledInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FIRST_PARTY_COOKIES));
198 int thirdPartyCookiesEnabledInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_THIRD_PARTY_COOKIES));
199 final int domStorageEnabledInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_DOM_STORAGE));
200 int formDataEnabledInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FORM_DATA)); // Form data can be remove once the minimum API >= 26.
201 int easyListEnabledInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_EASYLIST));
202 int easyPrivacyEnabledInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_EASYPRIVACY));
203 int fanboysAnnoyanceListInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FANBOYS_ANNOYANCE_LIST));
204 int fanboysSocialBlockingListInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FANBOYS_SOCIAL_BLOCKING_LIST));
205 int ultraPrivacyEnabledInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_ULTRAPRIVACY));
206 int blockAllThirdPartyRequestsInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.BLOCK_ALL_THIRD_PARTY_REQUESTS));
207 final String currentUserAgentName = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.USER_AGENT));
208 int fontSizeInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.FONT_SIZE));
209 int swipeToRefreshInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.SWIPE_TO_REFRESH));
210 int nightModeInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.NIGHT_MODE));
211 int displayImagesInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.DISPLAY_IMAGES));
212 int pinnedSslCertificateInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.PINNED_SSL_CERTIFICATE));
213 String savedSslCertificateIssuedToCNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_TO_COMMON_NAME));
214 String savedSslCertificateIssuedToONameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_TO_ORGANIZATION));
215 String savedSslCertificateIssuedToUNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_TO_ORGANIZATIONAL_UNIT));
216 String savedSslCertificateIssuedByCNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_BY_COMMON_NAME));
217 String savedSslCertificateIssuedByONameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_BY_ORGANIZATION));
218 String savedSslCertificateIssuedByUNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_BY_ORGANIZATIONAL_UNIT));
219 int pinnedIpAddressesInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.PINNED_IP_ADDRESSES));
220 String savedIpAddresses = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.IP_ADDRESSES));
222 // Initialize the saved SSL certificate date variables.
223 Date savedSslCertificateStartDate = null;
224 Date savedSslCertificateEndDate = null;
226 // Only get the saved SSL certificate dates from the cursor if they are not set to `0`.
227 if (domainCursor.getLong(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_START_DATE)) != 0) {
228 savedSslCertificateStartDate = new Date(domainCursor.getLong(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_START_DATE)));
231 if (domainCursor.getLong(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_END_DATE)) != 0) {
232 savedSslCertificateEndDate = new Date(domainCursor.getLong(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_END_DATE)));
235 // Create array adapters for the spinners.
236 ArrayAdapter<CharSequence> translatedUserAgentArrayAdapter = ArrayAdapter.createFromResource(context, R.array.translated_domain_settings_user_agent_names, R.layout.spinner_item);
237 ArrayAdapter<CharSequence> fontSizeArrayAdapter = ArrayAdapter.createFromResource(context, R.array.domain_settings_font_size_entries, R.layout.spinner_item);
238 ArrayAdapter<CharSequence> fontSizeEntryValuesArrayAdapter = ArrayAdapter.createFromResource(context, R.array.domain_settings_font_size_entry_values, R.layout.spinner_item);
239 ArrayAdapter<CharSequence> swipeToRefreshArrayAdapter = ArrayAdapter.createFromResource(context, R.array.swipe_to_refresh_array, R.layout.spinner_item);
240 ArrayAdapter<CharSequence> nightModeArrayAdapter = ArrayAdapter.createFromResource(context, R.array.night_mode_array, R.layout.spinner_item);
241 ArrayAdapter<CharSequence> displayImagesArrayAdapter = ArrayAdapter.createFromResource(context, R.array.display_webpage_images_array, R.layout.spinner_item);
243 // Set the drop down view resource on the spinners.
244 translatedUserAgentArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items);
245 fontSizeArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items);
246 swipeToRefreshArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items);
247 nightModeArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items);
248 displayImagesArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items);
250 // Set the array adapters for the spinners.
251 userAgentSpinner.setAdapter(translatedUserAgentArrayAdapter);
252 fontSizeSpinner.setAdapter(fontSizeArrayAdapter);
253 swipeToRefreshSpinner.setAdapter(swipeToRefreshArrayAdapter);
254 nightModeSpinner.setAdapter(nightModeArrayAdapter);
255 displayWebpageImagesSpinner.setAdapter(displayImagesArrayAdapter);
257 // Create a spannable string builder for each TextView that needs multiple colors of text.
258 SpannableStringBuilder savedSslCertificateIssuedToCNameStringBuilder = new SpannableStringBuilder(cNameLabel + savedSslCertificateIssuedToCNameString);
259 SpannableStringBuilder savedSslCertificateIssuedToONameStringBuilder = new SpannableStringBuilder(oNameLabel + savedSslCertificateIssuedToONameString);
260 SpannableStringBuilder savedSslCertificateIssuedToUNameStringBuilder = new SpannableStringBuilder(uNameLabel + savedSslCertificateIssuedToUNameString);
261 SpannableStringBuilder savedSslCertificateIssuedByCNameStringBuilder = new SpannableStringBuilder(cNameLabel + savedSslCertificateIssuedByCNameString);
262 SpannableStringBuilder savedSslCertificateIssuedByONameStringBuilder = new SpannableStringBuilder(oNameLabel + savedSslCertificateIssuedByONameString);
263 SpannableStringBuilder savedSslCertificateIssuedByUNameStringBuilder = new SpannableStringBuilder(uNameLabel + savedSslCertificateIssuedByUNameString);
265 // Initialize the spannable string builders for the SSL certificate dates.
266 SpannableStringBuilder savedSslCertificateStartDateStringBuilder;
267 SpannableStringBuilder savedSslCertificateEndDateStringBuilder;
269 // Leave the SSL certificate dates empty if they are `null`.
270 if (savedSslCertificateStartDate == null) {
271 savedSslCertificateStartDateStringBuilder = new SpannableStringBuilder(startDateLabel);
273 savedSslCertificateStartDateStringBuilder = new SpannableStringBuilder(startDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(savedSslCertificateStartDate));
276 if (savedSslCertificateEndDate == null) {
277 savedSslCertificateEndDateStringBuilder = new SpannableStringBuilder(endDateLabel);
279 savedSslCertificateEndDateStringBuilder = new SpannableStringBuilder(endDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(savedSslCertificateEndDate));
282 // Create a red foreground color span. The deprecated `resources.getColor` must be used until the minimum API >= 23.
283 final ForegroundColorSpan redColorSpan = new ForegroundColorSpan(resources.getColor(R.color.red_a700));
285 // Create a blue foreground color span.
286 final ForegroundColorSpan blueColorSpan;
288 // Set the blue color span according to the theme. The deprecated `resources.getColor` must be used until the minimum API >= 23.
289 if (MainWebViewActivity.darkTheme) {
290 //noinspection deprecation
291 blueColorSpan = new ForegroundColorSpan(resources.getColor(R.color.blue_400));
293 //noinspection deprecation
294 blueColorSpan = new ForegroundColorSpan(resources.getColor(R.color.blue_700));
297 // Set the domain name from the the database cursor.
298 domainNameEditText.setText(domainNameString);
300 // Update the certificates' `Common Name` color when the domain name text changes.
301 domainNameEditText.addTextChangedListener(new TextWatcher() {
303 public void beforeTextChanged(CharSequence s, int start, int count, int after) {
308 public void onTextChanged(CharSequence s, int start, int before, int count) {
313 public void afterTextChanged(Editable s) {
314 // Get the new domain name.
315 String newDomainName = domainNameEditText.getText().toString();
317 // Check the saved SSL certificate against the new domain name.
318 boolean savedSslCertificateMatchesNewDomainName = checkDomainNameAgainstCertificate(newDomainName, savedSslCertificateIssuedToCNameString);
320 // Create a `SpannableStringBuilder` for the saved certificate `Common Name`.
321 SpannableStringBuilder savedSslCertificateCommonNameStringBuilder = new SpannableStringBuilder(cNameLabel + savedSslCertificateIssuedToCNameString);
323 // Format the saved certificate `Common Name` color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
324 if (savedSslCertificateMatchesNewDomainName) {
325 savedSslCertificateCommonNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), savedSslCertificateCommonNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
327 savedSslCertificateCommonNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), savedSslCertificateCommonNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
330 // Update `savedSslCertificateIssuedToCNameTextView`.
331 savedSslCertificateIssuedToCNameTextView.setText(savedSslCertificateCommonNameStringBuilder);
333 // Update the current website certificate if it exists.
334 if (currentWebsiteSslCertificate != null) {
335 // Get the current website certificate `Common Name`.
336 String currentWebsiteCertificateCommonName = currentWebsiteSslCertificate.getIssuedTo().getCName();
338 // Check the current website certificate against the new domain name.
339 boolean currentWebsiteCertificateMatchesNewDomainName = checkDomainNameAgainstCertificate(newDomainName, currentWebsiteCertificateCommonName);
341 // Create a `SpannableStringBuilder` for the current website certificate `Common Name`.
342 SpannableStringBuilder currentWebsiteCertificateCommonNameStringBuilder = new SpannableStringBuilder(cNameLabel + currentWebsiteCertificateCommonName);
344 // Format the current certificate `Common Name` color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
345 if (currentWebsiteCertificateMatchesNewDomainName) {
346 currentWebsiteCertificateCommonNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), currentWebsiteCertificateCommonNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
348 currentWebsiteCertificateCommonNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), currentWebsiteCertificateCommonNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
351 // Update `currentWebsiteCertificateIssuedToCNameTextView`.
352 currentWebsiteCertificateIssuedToCNameTextView.setText(currentWebsiteCertificateCommonNameStringBuilder);
357 // Create a boolean to track if night mode is enabled.
358 boolean nightModeEnabled = (nightModeInt == DomainsDatabaseHelper.NIGHT_MODE_ENABLED) || ((nightModeInt == DomainsDatabaseHelper.NIGHT_MODE_SYSTEM_DEFAULT) && defaultNightMode);
360 // Disable the JavaScript switch if night mode is enabled.
361 if (nightModeEnabled) {
362 javaScriptEnabledSwitch.setEnabled(false);
364 javaScriptEnabledSwitch.setEnabled(true);
367 // Set the JavaScript icon.
368 if ((javaScriptEnabledInt == 1) || nightModeEnabled) {
369 javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.javascript_enabled));
371 javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.privacy_mode));
374 // Set the JavaScript switch status.
375 if (javaScriptEnabledInt == 1) { // JavaScript is enabled.
376 javaScriptEnabledSwitch.setChecked(true);
377 } else { // JavaScript is disabled.
378 javaScriptEnabledSwitch.setChecked(false);
381 // 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.
382 if (firstPartyCookiesEnabledInt == 1) { // First-party cookies are enabled.
383 firstPartyCookiesEnabledSwitch.setChecked(true);
384 firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_enabled));
385 } else { // First-party cookies are disabled.
386 firstPartyCookiesEnabledSwitch.setChecked(false);
388 // Set the icon according to the theme.
389 if (MainWebViewActivity.darkTheme) {
390 firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_dark));
392 firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_light));
396 // Only display third-party cookies if SDK_INT >= 21.
397 if (Build.VERSION.SDK_INT >= 21) { // Third-party cookies can be configured for API >= 21.
398 // Only enable third-party-cookies if first-party cookies are enabled.
399 if (firstPartyCookiesEnabledInt == 1) { // First-party cookies are enabled.
400 // 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.
401 if (thirdPartyCookiesEnabledInt == 1) { // Both first-party and third-party cookies are enabled.
402 thirdPartyCookiesEnabledSwitch.setChecked(true);
403 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_warning));
404 } else { // First party cookies are enabled but third-party cookies are disabled.
405 thirdPartyCookiesEnabledSwitch.setChecked(false);
407 // Set the icon according to the theme.
408 if (MainWebViewActivity.darkTheme) {
409 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_dark));
411 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_light));
414 } else { // First-party cookies are disabled.
415 // Set the status of third-party cookies.
416 if (thirdPartyCookiesEnabledInt == 1) {
417 thirdPartyCookiesEnabledSwitch.setChecked(true);
419 thirdPartyCookiesEnabledSwitch.setChecked(false);
422 // Disable the third-party cookies switch.
423 thirdPartyCookiesEnabledSwitch.setEnabled(false);
425 // Set the icon according to the theme.
426 if (MainWebViewActivity.darkTheme) {
427 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_ghosted_dark));
429 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_ghosted_light));
432 } else { // Third-party cookies cannot be configured for API <= 21.
433 // Hide the LinearLayout for third-party cookies.
434 thirdPartyCookiesLinearLayout.setVisibility(View.GONE);
437 // Only enable DOM storage if JavaScript is enabled.
438 if ((javaScriptEnabledInt == 1) || nightModeEnabled) { // JavaScript is enabled.
439 // Enable the DOM storage `Switch`.
440 domStorageEnabledSwitch.setEnabled(true);
442 // Set the DOM storage status. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
443 if (domStorageEnabledInt == 1) { // Both JavaScript and DOM storage are enabled.
444 domStorageEnabledSwitch.setChecked(true);
445 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_enabled));
446 } else { // JavaScript is enabled but DOM storage is disabled.
447 // Set the DOM storage switch to off.
448 domStorageEnabledSwitch.setChecked(false);
450 // Set the icon according to the theme.
451 if (MainWebViewActivity.darkTheme) {
452 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_dark));
454 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_light));
457 } else { // JavaScript is disabled.
458 // Disable the DOM storage `Switch`.
459 domStorageEnabledSwitch.setEnabled(false);
461 // Set the checked status of DOM storage.
462 if (domStorageEnabledInt == 1) { // DOM storage is enabled but JavaScript is disabled.
463 domStorageEnabledSwitch.setChecked(true);
464 } else { // Both JavaScript and DOM storage are disabled.
465 domStorageEnabledSwitch.setChecked(false);
468 // Set the icon according to the theme.
469 if (MainWebViewActivity.darkTheme) {
470 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_dark));
472 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_light));
476 // 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.
477 if (Build.VERSION.SDK_INT >= 26) { // Form data no longer applies to newer versions of Android.
478 // Hide the form data switch.
479 formDataEnabledSwitch.setVisibility(View.GONE);
480 } else { // Form data should be displayed because this is an older version of Android.
481 if (formDataEnabledInt == 1) { // Form data is on.
482 formDataEnabledSwitch.setChecked(true);
483 formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_enabled));
484 } else { // Form data is off.
485 // Turn the form data switch to off.
486 formDataEnabledSwitch.setChecked(false);
488 // Set the icon according to the theme.
489 if (MainWebViewActivity.darkTheme) {
490 formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_disabled_dark));
492 formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_disabled_light));
497 // Set the EasyList status. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
498 if (easyListEnabledInt == 1) { // EasyList is on.
499 // Turn the switch on.
500 easyListSwitch.setChecked(true);
502 // Set the icon according to the theme.
503 if (MainWebViewActivity.darkTheme) {
504 easyListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_enabled_dark));
506 easyListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_enabled_light));
508 } else { // EasyList is off.
509 // Turn the switch off.
510 easyListSwitch.setChecked(false);
512 // Set the icon according to the theme.
513 if (MainWebViewActivity.darkTheme) {
514 easyListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_disabled_dark));
516 easyListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_disabled_light));
520 // Set the EasyPrivacy status. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
521 if (easyPrivacyEnabledInt == 1) { // EasyPrivacy is on.
522 // Turn the switch on.
523 easyPrivacySwitch.setChecked(true);
525 // Set the icon according to the theme.
526 if (MainWebViewActivity.darkTheme) {
527 easyPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_enabled_dark));
529 easyPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_enabled_light));
531 } else { // EasyPrivacy is off.
532 // Turn the switch off.
533 easyPrivacySwitch.setChecked(false);
535 // Set the icon according to the theme.
536 if (MainWebViewActivity.darkTheme) {
537 easyPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_disabled_dark));
539 easyPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_disabled_light));
543 // 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.
544 if (fanboysAnnoyanceListInt == 1) { // Fanboy's Annoyance List is on.
545 // Turn the switch on.
546 fanboysAnnoyanceListSwitch.setChecked(true);
548 // Set the icon according to the theme.
549 if (MainWebViewActivity.darkTheme) {
550 fanboysAnnoyanceListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_dark));
552 fanboysAnnoyanceListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_light));
554 } else { // Fanboy's Annoyance List is off.
555 // Turn the switch off.
556 fanboysAnnoyanceListSwitch.setChecked(false);
558 // Set the icon according to the theme.
559 if (MainWebViewActivity.darkTheme) {
560 fanboysAnnoyanceListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_dark));
562 fanboysAnnoyanceListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_light));
566 // Only enable Fanboy's Social Blocking List if Fanboy's Annoyance List is off.
567 if (fanboysAnnoyanceListInt == 0) { // Fanboy's Annoyance List is on.
568 // 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.
569 if (fanboysSocialBlockingListInt == 1) { // Fanboy's Social Blocking List is on.
570 // Enable the switch and turn it on.
571 fanboysSocialBlockingListSwitch.setEnabled(true);
572 fanboysSocialBlockingListSwitch.setChecked(true);
574 // Set the icon according to the theme.
575 if (MainWebViewActivity.darkTheme) {
576 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_dark));
578 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_light));
580 } else { // Fanboy's Social Blocking List is off.
581 // Enable the switch but turn it off.
582 fanboysSocialBlockingListSwitch.setEnabled(true);
583 fanboysSocialBlockingListSwitch.setChecked(false);
585 // Set the icon according to the theme.
586 if (MainWebViewActivity.darkTheme) {
587 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_dark));
589 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_light));
592 } else { // Fanboy's Annoyance List is on.
593 // 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.
594 if (fanboysSocialBlockingListInt == 1) { // Fanboy's Social Blocking List is on.
595 // Disable the switch but turn it on.
596 fanboysSocialBlockingListSwitch.setEnabled(false);
597 fanboysSocialBlockingListSwitch.setChecked(true);
598 } else { // Fanboy's Social Blocking List is off.
599 // Disable the switch and turn it off.
600 fanboysSocialBlockingListSwitch.setEnabled(false);
601 fanboysSocialBlockingListSwitch.setChecked(false);
604 // Set the icon according to the theme.
605 if (MainWebViewActivity.darkTheme) {
606 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_ghosted_dark));
608 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_ghosted_light));
612 // Set the UltraPrivacy status. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
613 if (ultraPrivacyEnabledInt == 1) { // UltraPrivacy is on.
614 // Turn the switch on.
615 ultraPrivacySwitch.setChecked(true);
617 // Set the icon according to the theme.
618 if (MainWebViewActivity.darkTheme) {
619 ultraPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_enabled_dark));
621 ultraPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_enabled_light));
623 } else { // EasyPrivacy is off.
624 // Turn the switch off.
625 ultraPrivacySwitch.setChecked(false);
627 // Set the icon according to the theme.
628 if (MainWebViewActivity.darkTheme) {
629 ultraPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_disabled_dark));
631 ultraPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_disabled_light));
635 // 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.
636 if (blockAllThirdPartyRequestsInt == 1) { // Blocking all third-party requests is on.
637 // Turn the switch on.
638 blockAllThirdPartyRequestsSwitch.setChecked(true);
640 // Set the icon according to the theme.
641 if (MainWebViewActivity.darkTheme) {
642 blockAllThirdPartyRequestsImageView.setImageDrawable(resources.getDrawable(R.drawable.block_all_third_party_requests_enabled_dark));
644 blockAllThirdPartyRequestsImageView.setImageDrawable(resources.getDrawable(R.drawable.block_all_third_party_requests_enabled_light));
646 } else { // Blocking all third-party requests is off.
647 // Turn the switch off.
648 blockAllThirdPartyRequestsSwitch.setChecked(false);
650 // Set the icon according to the theme.
651 if (MainWebViewActivity.darkTheme) {
652 blockAllThirdPartyRequestsImageView.setImageDrawable(resources.getDrawable(R.drawable.block_all_third_party_requests_disabled_dark));
654 blockAllThirdPartyRequestsImageView.setImageDrawable(resources.getDrawable(R.drawable.block_all_third_party_requests_disabled_light));
658 // Inflated a WebView to get the default user agent.
659 // `@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.
660 @SuppressLint("InflateParams") View bareWebViewLayout = inflater.inflate(R.layout.bare_webview, null, false);
661 WebView bareWebView = bareWebViewLayout.findViewById(R.id.bare_webview);
662 final String webViewDefaultUserAgentString = bareWebView.getSettings().getUserAgentString();
664 // Get a handle for the user agent array adapter. This array does not contain the `System default` entry.
665 ArrayAdapter<CharSequence> userAgentNamesArray = ArrayAdapter.createFromResource(context, R.array.user_agent_names, R.layout.spinner_item);
667 // Get the positions of the user agent and the default user agent.
668 int userAgentArrayPosition = userAgentNamesArray.getPosition(currentUserAgentName);
669 int defaultUserAgentArrayPosition = userAgentNamesArray.getPosition(defaultUserAgentName);
671 // Get a handle for the user agent data array. This array does not contain the `System default` entry.
672 String[] userAgentDataArray = resources.getStringArray(R.array.user_agent_data);
674 // Set the user agent text.
675 if (currentUserAgentName.equals(getString(R.string.system_default_user_agent))) { // Use the system default user agent.
676 // Set the user agent according to the system default.
677 switch (defaultUserAgentArrayPosition) {
678 case MainWebViewActivity.UNRECOGNIZED_USER_AGENT: // The default user agent name is not on the canonical list.
679 // This is probably because it was set in an older version of Privacy Browser before the switch to persistent user agent names.
680 userAgentTextView.setText(defaultUserAgentName);
683 case MainWebViewActivity.SETTINGS_WEBVIEW_DEFAULT_USER_AGENT:
684 // Display the `WebView` default user agent.
685 userAgentTextView.setText(webViewDefaultUserAgentString);
688 case MainWebViewActivity.SETTINGS_CUSTOM_USER_AGENT:
689 // Display the custom user agent.
690 userAgentTextView.setText(defaultCustomUserAgentString);
694 // Get the user agent string from the user agent data array.
695 userAgentTextView.setText(userAgentDataArray[defaultUserAgentArrayPosition]);
697 } else if (userAgentArrayPosition == MainWebViewActivity.UNRECOGNIZED_USER_AGENT) { // A custom user agent is stored in the current user agent name.
698 // Set the user agent spinner to `Custom user agent`.
699 userAgentSpinner.setSelection(MainWebViewActivity.DOMAINS_CUSTOM_USER_AGENT);
701 // Hide the user agent TextView.
702 userAgentTextView.setVisibility(View.GONE);
704 // Show the custom user agent EditText and set the current user agent name as the text.
705 customUserAgentEditText.setVisibility(View.VISIBLE);
706 customUserAgentEditText.setText(currentUserAgentName);
707 } else { // The user agent name contains one of the canonical user agents.
708 // 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.
709 userAgentSpinner.setSelection(userAgentArrayPosition + 1);
711 // Show the user agent TextView.
712 userAgentTextView.setVisibility(View.VISIBLE);
714 // Hide the custom user agent EditText.
715 customUserAgentEditText.setVisibility(View.GONE);
717 // Set the user agent text.
718 switch (userAgentArrayPosition) {
719 case MainWebViewActivity.DOMAINS_WEBVIEW_DEFAULT_USER_AGENT:
720 // Display the WebView default user agent.
721 userAgentTextView.setText(webViewDefaultUserAgentString);
725 // 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.
726 userAgentTextView.setText(userAgentDataArray[userAgentArrayPosition + 1]);
730 // Open the user agent spinner when the TextView is clicked.
731 userAgentTextView.setOnClickListener((View v) -> {
732 // Open the user agent spinner.
733 userAgentSpinner.performClick();
736 // Set the selected font size.
737 int fontSizeArrayPosition = fontSizeEntryValuesArrayAdapter.getPosition(String.valueOf(fontSizeInt));
738 fontSizeSpinner.setSelection(fontSizeArrayPosition);
740 // Set the default font size text.
741 int defaultFontSizeArrayPosition = fontSizeEntryValuesArrayAdapter.getPosition(defaultFontSizeString);
742 fontSizeTextView.setText(fontSizeArrayAdapter.getItem(defaultFontSizeArrayPosition));
744 // Set the display options for the font size TextView.
745 if (fontSizeArrayPosition == 0) { // System default font size is selected. Display `fontSizeTextView`.
746 fontSizeTextView.setVisibility(View.VISIBLE);
747 } else { // A custom font size is specified. Hide `fontSizeTextView`.
748 fontSizeTextView.setVisibility(View.GONE);
751 // Open the font size spinner when the TextView is clicked.
752 fontSizeTextView.setOnClickListener((View v) -> {
753 // Open the user agent spinner.
754 fontSizeSpinner.performClick();
757 // Display the swipe to refresh selection in the spinner.
758 swipeToRefreshSpinner.setSelection(swipeToRefreshInt);
760 // Set the swipe to refresh text.
761 if (defaultSwipeToRefresh) {
762 swipeToRefreshTextView.setText(swipeToRefreshArrayAdapter.getItem(DomainsDatabaseHelper.SWIPE_TO_REFRESH_ENABLED));
764 swipeToRefreshTextView.setText(swipeToRefreshArrayAdapter.getItem(DomainsDatabaseHelper.SWIPE_TO_REFRESH_DISABLED));
767 // 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.
768 switch (swipeToRefreshInt) {
769 case DomainsDatabaseHelper.SWIPE_TO_REFRESH_SYSTEM_DEFAULT:
770 if (defaultSwipeToRefresh) { // Swipe to refresh is enabled by default.
771 // Set the icon according to the theme.
772 if (MainWebViewActivity.darkTheme) {
773 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_enabled_dark));
775 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_enabled_light));
777 } else { // Swipe to refresh is disabled by default
778 // Set the icon according to the theme.
779 if (MainWebViewActivity.darkTheme) {
780 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_disabled_dark));
782 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_disabled_light));
786 // Show the swipe to refresh TextView.
787 swipeToRefreshTextView.setVisibility(View.VISIBLE);
790 case DomainsDatabaseHelper.SWIPE_TO_REFRESH_ENABLED:
791 // Set the icon according to the theme.
792 if (MainWebViewActivity.darkTheme) {
793 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_enabled_dark));
795 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_enabled_light));
798 // Hide the swipe to refresh TextView.`
799 swipeToRefreshTextView.setVisibility(View.GONE);
802 case DomainsDatabaseHelper.SWIPE_TO_REFRESH_DISABLED:
803 // Set the icon according to the theme.
804 if (MainWebViewActivity.darkTheme) {
805 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_disabled_dark));
807 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_disabled_light));
810 // Hide the swipe to refresh TextView.
811 swipeToRefreshTextView.setVisibility(View.GONE);
814 // Open the swipe to refresh spinner when the TextView is clicked.
815 swipeToRefreshTextView.setOnClickListener((View v) -> {
816 // Open the swipe to refresh spinner.
817 swipeToRefreshSpinner.performClick();
820 // Display the night mode in the spinner.
821 nightModeSpinner.setSelection(nightModeInt);
823 // Set the default night mode text.
824 if (defaultNightMode) {
825 nightModeTextView.setText(nightModeArrayAdapter.getItem(DomainsDatabaseHelper.NIGHT_MODE_ENABLED));
827 nightModeTextView.setText(nightModeArrayAdapter.getItem(DomainsDatabaseHelper.NIGHT_MODE_DISABLED));
830 // 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.
831 switch (nightModeInt) {
832 case DomainsDatabaseHelper.NIGHT_MODE_SYSTEM_DEFAULT:
833 if (defaultNightMode) { // Night mode enabled by default.
834 // Set the icon according to the theme.
835 if (MainWebViewActivity.darkTheme) {
836 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_dark));
838 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_light));
840 } else { // Night mode disabled by default.
841 // Set the icon according to the theme.
842 if (MainWebViewActivity.darkTheme) {
843 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_dark));
845 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_light));
849 // Show night mode TextView.
850 nightModeTextView.setVisibility(View.VISIBLE);
853 case DomainsDatabaseHelper.NIGHT_MODE_ENABLED:
854 // Set the icon according to the theme.
855 if (MainWebViewActivity.darkTheme) {
856 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_dark));
858 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_light));
861 // Hide the night mode TextView.
862 nightModeTextView.setVisibility(View.GONE);
865 case DomainsDatabaseHelper.NIGHT_MODE_DISABLED:
866 // Set the icon according to the theme.
867 if (MainWebViewActivity.darkTheme) {
868 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_dark));
870 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_light));
873 // Hide the night mode TextView.
874 nightModeTextView.setVisibility(View.GONE);
878 // Open the night mode spinner when the TextView is clicked.
879 nightModeTextView.setOnClickListener((View v) -> {
880 // Open the night mode spinner.
881 nightModeSpinner.performClick();
884 // Display the website images mode in the spinner.
885 displayWebpageImagesSpinner.setSelection(displayImagesInt);
887 // Set the default display images text.
888 if (defaultDisplayWebpageImages) {
889 displayImagesTextView.setText(displayImagesArrayAdapter.getItem(DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_ENABLED));
891 displayImagesTextView.setText(displayImagesArrayAdapter.getItem(DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_DISABLED));
894 // 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.
895 switch (displayImagesInt) {
896 case DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_SYSTEM_DEFAULT:
897 if (defaultDisplayWebpageImages) { // Display webpage images enabled by default.
898 // Set the icon according to the theme.
899 if (MainWebViewActivity.darkTheme) {
900 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_dark));
902 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_light));
904 } else { // Display webpage images disabled by default.
905 // Set the icon according to the theme.
906 if (MainWebViewActivity.darkTheme) {
907 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_dark));
909 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_light));
913 // Show the display images TextView.
914 displayImagesTextView.setVisibility(View.VISIBLE);
917 case DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_ENABLED:
918 // Set the icon according to the theme.
919 if (MainWebViewActivity.darkTheme) {
920 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_dark));
922 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_light));
925 // Hide the display images TextView.
926 displayImagesTextView.setVisibility(View.GONE);
929 case DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_DISABLED:
930 // Set the icon according to the theme.
931 if (MainWebViewActivity.darkTheme) {
932 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_dark));
934 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_light));
937 // Hide the display images TextView.
938 displayImagesTextView.setVisibility(View.GONE);
942 // Open the display images spinner when the TextView is clicked.
943 displayImagesTextView.setOnClickListener((View v) -> {
944 // Open the user agent spinner.
945 displayWebpageImagesSpinner.performClick();
948 // Set the pinned SSL certificate icon.
949 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.
951 pinnedSslCertificateSwitch.setChecked(true);
953 // Set the icon according to the theme.
954 if (MainWebViewActivity.darkTheme) {
955 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_dark));
957 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_light));
959 } else { // Pinned SSL certificate is disabled.
960 // Uncheck the switch.
961 pinnedSslCertificateSwitch.setChecked(false);
963 // Set the icon according to the theme.
964 if (MainWebViewActivity.darkTheme) {
965 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_dark));
967 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_light));
971 // Store the current date.
972 Date currentDate = Calendar.getInstance().getTime();
974 // Setup the string builders to display the general certificate information in blue. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
975 savedSslCertificateIssuedToONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), savedSslCertificateIssuedToONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
976 savedSslCertificateIssuedToUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), savedSslCertificateIssuedToUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
977 savedSslCertificateIssuedByCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), savedSslCertificateIssuedByCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
978 savedSslCertificateIssuedByONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), savedSslCertificateIssuedByONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
979 savedSslCertificateIssuedByUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), savedSslCertificateIssuedByUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
981 // Check the certificate Common Name against the domain name.
982 boolean savedSSlCertificateCommonNameMatchesDomainName = checkDomainNameAgainstCertificate(domainNameString, savedSslCertificateIssuedToCNameString);
984 // Format the issued to Common Name color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
985 if (savedSSlCertificateCommonNameMatchesDomainName) {
986 savedSslCertificateIssuedToCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), savedSslCertificateIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
988 savedSslCertificateIssuedToCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), savedSslCertificateIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
991 // Format the start date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
992 if ((savedSslCertificateStartDate != null) && savedSslCertificateStartDate.after(currentDate)) { // The certificate start date is in the future.
993 savedSslCertificateStartDateStringBuilder.setSpan(redColorSpan, startDateLabel.length(), savedSslCertificateStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
994 } else { // The certificate start date is in the past.
995 savedSslCertificateStartDateStringBuilder.setSpan(blueColorSpan, startDateLabel.length(), savedSslCertificateStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
998 // Format the end date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
999 if ((savedSslCertificateEndDate != null) && savedSslCertificateEndDate.before(currentDate)) { // The certificate end date is in the past.
1000 savedSslCertificateEndDateStringBuilder.setSpan(redColorSpan, endDateLabel.length(), savedSslCertificateEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1001 } else { // The certificate end date is in the future.
1002 savedSslCertificateEndDateStringBuilder.setSpan(blueColorSpan, endDateLabel.length(), savedSslCertificateEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1005 // Display the saved website SSL certificate strings.
1006 savedSslCertificateIssuedToCNameTextView.setText(savedSslCertificateIssuedToCNameStringBuilder);
1007 savedSslCertificateIssuedToONameTextView.setText(savedSslCertificateIssuedToONameStringBuilder);
1008 savedSslCertificateIssuedToUNameTextView.setText(savedSslCertificateIssuedToUNameStringBuilder);
1009 savedSslCertificateIssuedByCNameTextView.setText(savedSslCertificateIssuedByCNameStringBuilder);
1010 savedSslCertificateIssuedByONameTextView.setText(savedSslCertificateIssuedByONameStringBuilder);
1011 savedSslCertificateIssuedByUNameTextView.setText(savedSslCertificateIssuedByUNameStringBuilder);
1012 savedSslCertificateStartDateTextView.setText(savedSslCertificateStartDateStringBuilder);
1013 savedSslCertificateEndDateTextView.setText(savedSslCertificateEndDateStringBuilder);
1015 // Populate the current website SSL certificate if there is one.
1016 if (currentWebsiteSslCertificate != null) {
1017 // Get the strings from the SSL certificate.
1018 String currentWebsiteCertificateIssuedToCNameString = currentWebsiteSslCertificate.getIssuedTo().getCName();
1019 String currentWebsiteCertificateIssuedToONameString = currentWebsiteSslCertificate.getIssuedTo().getOName();
1020 String currentWebsiteCertificateIssuedToUNameString = currentWebsiteSslCertificate.getIssuedTo().getUName();
1021 String currentWebsiteCertificateIssuedByCNameString = currentWebsiteSslCertificate.getIssuedBy().getCName();
1022 String currentWebsiteCertificateIssuedByONameString = currentWebsiteSslCertificate.getIssuedBy().getOName();
1023 String currentWebsiteCertificateIssuedByUNameString = currentWebsiteSslCertificate.getIssuedBy().getUName();
1024 Date currentWebsiteCertificateStartDate = currentWebsiteSslCertificate.getValidNotBeforeDate();
1025 Date currentWebsiteCertificateEndDate = currentWebsiteSslCertificate.getValidNotAfterDate();
1027 // Create a spannable string builder for each text view that needs multiple colors of text.
1028 SpannableStringBuilder currentWebsiteCertificateIssuedToCNameStringBuilder = new SpannableStringBuilder(cNameLabel + currentWebsiteCertificateIssuedToCNameString);
1029 SpannableStringBuilder currentWebsiteCertificateIssuedToONameStringBuilder = new SpannableStringBuilder(oNameLabel + currentWebsiteCertificateIssuedToONameString);
1030 SpannableStringBuilder currentWebsiteCertificateIssuedToUNameStringBuilder = new SpannableStringBuilder(uNameLabel + currentWebsiteCertificateIssuedToUNameString);
1031 SpannableStringBuilder currentWebsiteCertificateIssuedByCNameStringBuilder = new SpannableStringBuilder(cNameLabel + currentWebsiteCertificateIssuedByCNameString);
1032 SpannableStringBuilder currentWebsiteCertificateIssuedByONameStringBuilder = new SpannableStringBuilder(oNameLabel + currentWebsiteCertificateIssuedByONameString);
1033 SpannableStringBuilder currentWebsiteCertificateIssuedByUNameStringBuilder = new SpannableStringBuilder(uNameLabel + currentWebsiteCertificateIssuedByUNameString);
1034 SpannableStringBuilder currentWebsiteCertificateStartDateStringBuilder = new SpannableStringBuilder(startDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG)
1035 .format(currentWebsiteCertificateStartDate));
1036 SpannableStringBuilder currentWebsiteCertificateEndDateStringBuilder = new SpannableStringBuilder(endDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG)
1037 .format(currentWebsiteCertificateEndDate));
1039 // Setup the string builders to display the general certificate information in blue. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
1040 currentWebsiteCertificateIssuedToONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), currentWebsiteCertificateIssuedToONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1041 currentWebsiteCertificateIssuedToUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), currentWebsiteCertificateIssuedToUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1042 currentWebsiteCertificateIssuedByCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), currentWebsiteCertificateIssuedByCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1043 currentWebsiteCertificateIssuedByONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), currentWebsiteCertificateIssuedByONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1044 currentWebsiteCertificateIssuedByUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), currentWebsiteCertificateIssuedByUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1046 // Check the certificate Common Name against the domain name.
1047 boolean currentWebsiteCertificateCommonNameMatchesDomainName = checkDomainNameAgainstCertificate(domainNameString, currentWebsiteCertificateIssuedToCNameString);
1049 // Format the issued to Common Name color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
1050 if (currentWebsiteCertificateCommonNameMatchesDomainName) {
1051 currentWebsiteCertificateIssuedToCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), currentWebsiteCertificateIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1053 currentWebsiteCertificateIssuedToCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), currentWebsiteCertificateIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1056 // Format the start date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
1057 if (currentWebsiteCertificateStartDate.after(currentDate)) { // The certificate start date is in the future.
1058 currentWebsiteCertificateStartDateStringBuilder.setSpan(redColorSpan, startDateLabel.length(), currentWebsiteCertificateStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1059 } else { // The certificate start date is in the past.
1060 currentWebsiteCertificateStartDateStringBuilder.setSpan(blueColorSpan, startDateLabel.length(), currentWebsiteCertificateStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1063 // Format the end date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
1064 if (currentWebsiteCertificateEndDate.before(currentDate)) { // The certificate end date is in the past.
1065 currentWebsiteCertificateEndDateStringBuilder.setSpan(redColorSpan, endDateLabel.length(), currentWebsiteCertificateEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1066 } else { // The certificate end date is in the future.
1067 currentWebsiteCertificateEndDateStringBuilder.setSpan(blueColorSpan, endDateLabel.length(), currentWebsiteCertificateEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1070 // Display the current website SSL certificate strings.
1071 currentWebsiteCertificateIssuedToCNameTextView.setText(currentWebsiteCertificateIssuedToCNameStringBuilder);
1072 currentWebsiteCertificateIssuedToONameTextView.setText(currentWebsiteCertificateIssuedToONameStringBuilder);
1073 currentWebsiteCertificateIssuedToUNameTextView.setText(currentWebsiteCertificateIssuedToUNameStringBuilder);
1074 currentWebsiteCertificateIssuedByCNameTextView.setText(currentWebsiteCertificateIssuedByCNameStringBuilder);
1075 currentWebsiteCertificateIssuedByONameTextView.setText(currentWebsiteCertificateIssuedByONameStringBuilder);
1076 currentWebsiteCertificateIssuedByUNameTextView.setText(currentWebsiteCertificateIssuedByUNameStringBuilder);
1077 currentWebsiteCertificateStartDateTextView.setText(currentWebsiteCertificateStartDateStringBuilder);
1078 currentWebsiteCertificateEndDateTextView.setText(currentWebsiteCertificateEndDateStringBuilder);
1081 // Set the initial display status of the SSL certificates card views.
1082 if (pinnedSslCertificateSwitch.isChecked()) { // An SSL certificate is pinned.
1083 // Set the visibility of the saved SSL certificate.
1084 if (savedSslCertificateIssuedToCNameString == null) {
1085 savedSslCertificateCardView.setVisibility(View.GONE);
1087 savedSslCertificateCardView.setVisibility(View.VISIBLE);
1090 // Set the visibility of the current website SSL certificate.
1091 if (currentWebsiteSslCertificate == null) { // There is no current SSL certificate.
1092 // Hide the SSL certificate.
1093 currentWebsiteCertificateCardView.setVisibility(View.GONE);
1095 // Show the instruction.
1096 noCurrentWebsiteCertificateTextView.setVisibility(View.VISIBLE);
1097 } else { // There is a current SSL certificate.
1098 // Show the SSL certificate.
1099 currentWebsiteCertificateCardView.setVisibility(View.VISIBLE);
1101 // Hide the instruction.
1102 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
1105 // Set the status of the radio buttons and the card view backgrounds.
1106 if (savedSslCertificateCardView.getVisibility() == View.VISIBLE) { // The saved SSL certificate is displayed.
1107 // Check the saved SSL certificate radio button.
1108 savedSslCertificateRadioButton.setChecked(true);
1110 // Uncheck the current website SSL certificate radio button.
1111 currentWebsiteCertificateRadioButton.setChecked(false);
1113 // Darken the background of the current website SSL certificate linear layout according to the theme.
1114 if (MainWebViewActivity.darkTheme) {
1115 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1117 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1119 } else if (currentWebsiteCertificateCardView.getVisibility() == View.VISIBLE) { // The saved SSL certificate is hidden but the current website SSL certificate is visible.
1120 // Check the current website SSL certificate radio button.
1121 currentWebsiteCertificateRadioButton.setChecked(true);
1123 // Uncheck the saved SSL certificate radio button.
1124 savedSslCertificateRadioButton.setChecked(false);
1125 } else { // Neither SSL certificate is visible.
1126 // Uncheck both radio buttons.
1127 savedSslCertificateRadioButton.setChecked(false);
1128 currentWebsiteCertificateRadioButton.setChecked(false);
1130 } else { // An SSL certificate is not pinned.
1131 // Hide the SSl certificates and instructions.
1132 savedSslCertificateCardView.setVisibility(View.GONE);
1133 currentWebsiteCertificateCardView.setVisibility(View.GONE);
1134 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
1136 // Uncheck the radio buttons.
1137 savedSslCertificateRadioButton.setChecked(false);
1138 currentWebsiteCertificateRadioButton.setChecked(false);
1141 // Set the pinned IP addresses icon.
1142 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.
1143 // Check the switch.
1144 pinnedIpAddressesSwitch.setChecked(true);
1146 // Set the icon according to the theme.
1147 if (MainWebViewActivity.darkTheme) {
1148 pinnedIpAddressesImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_dark));
1150 pinnedIpAddressesImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_light));
1152 } else { // Pinned IP Addresses is disabled.
1153 // Uncheck the switch.
1154 pinnedIpAddressesSwitch.setChecked(false);
1156 // Set the icon according to the theme.
1157 if (MainWebViewActivity.darkTheme) {
1158 pinnedIpAddressesImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_dark));
1160 pinnedIpAddressesImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_light));
1164 // Populate the saved and current IP addresses.
1165 savedIpAddressesTextView.setText(savedIpAddresses);
1166 currentIpAddressesTextView.setText(MainWebViewActivity.currentHostIpAddresses);
1168 // Set the initial display status of the IP addresses card views.
1169 if (pinnedIpAddressesSwitch.isChecked()) { // IP addresses are pinned.
1170 // Set the visibility of the saved IP addresses.
1171 if (savedIpAddresses == null) { // There are no saved IP addresses.
1172 savedIpAddressesCardView.setVisibility(View.GONE);
1173 } else { // There are saved IP addresses.
1174 savedIpAddressesCardView.setVisibility(View.VISIBLE);
1177 // Set the visibility of the current IP addresses.
1178 currentIpAddressesCardView.setVisibility(View.VISIBLE);
1180 // Set the status of the radio buttons and the card view backgrounds.
1181 if (savedIpAddressesCardView.getVisibility() == View.VISIBLE) { // The saved IP addresses are displayed.
1182 // Check the saved IP addresses radio button.
1183 savedIpAddressesRadioButton.setChecked(true);
1185 // Uncheck the current IP addresses radio button.
1186 currentIpAddressesRadioButton.setChecked(false);
1188 // Darken the background of the current IP addresses linear layout according to the theme.
1189 if (MainWebViewActivity.darkTheme) {
1190 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1192 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1194 } else { // The saved IP addresses are hidden.
1195 // Check the current IP addresses radio button.
1196 currentIpAddressesRadioButton.setChecked(true);
1198 // Uncheck the saved IP addresses radio button.
1199 savedIpAddressesRadioButton.setChecked(false);
1201 } else { // IP addresses are not pinned.
1202 // Hide the IP addresses card views.
1203 savedIpAddressesCardView.setVisibility(View.GONE);
1204 currentIpAddressesCardView.setVisibility(View.GONE);
1206 // Uncheck the radio buttons.
1207 savedIpAddressesRadioButton.setChecked(false);
1208 currentIpAddressesRadioButton.setChecked(false);
1212 // Set the JavaScript switch listener.
1213 javaScriptEnabledSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1214 if (isChecked) { // JavaScript is enabled.
1215 // Update the JavaScript icon.
1216 javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.javascript_enabled));
1218 // Enable the DOM storage `Switch`.
1219 domStorageEnabledSwitch.setEnabled(true);
1221 // Update the DOM storage icon.
1222 if (domStorageEnabledSwitch.isChecked()) { // DOM storage is enabled.
1223 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_enabled));
1224 } else { // DOM storage is disabled.
1225 // Set the icon according to the theme.
1226 if (MainWebViewActivity.darkTheme) {
1227 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_dark));
1229 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_light));
1232 } else { // JavaScript is disabled.
1233 // Update the JavaScript icon.
1234 javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.privacy_mode));
1236 // Disable the DOM storage `Switch`.
1237 domStorageEnabledSwitch.setEnabled(false);
1239 // Set the DOM storage icon according to the theme.
1240 if (MainWebViewActivity.darkTheme) {
1241 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_dark));
1243 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_light));
1248 // Set the first-party cookies switch listener.
1249 firstPartyCookiesEnabledSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1250 if (isChecked) { // First-party cookies are enabled.
1251 // Update the first-party cookies icon.
1252 firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_enabled));
1254 // Enable the third-party cookies switch.
1255 thirdPartyCookiesEnabledSwitch.setEnabled(true);
1257 // Update the third-party cookies icon.
1258 if (thirdPartyCookiesEnabledSwitch.isChecked()) { // Third-party cookies are enabled.
1259 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_warning));
1260 } else { // Third-party cookies are disabled.
1261 // Set the third-party cookies icon according to the theme.
1262 if (MainWebViewActivity.darkTheme) {
1263 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_dark));
1265 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_light));
1268 } else { // First-party cookies are disabled.
1269 // Update the first-party cookies icon according to the theme.
1270 if (MainWebViewActivity.darkTheme) {
1271 firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_dark));
1273 firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_light));
1276 // Disable the third-party cookies switch.
1277 thirdPartyCookiesEnabledSwitch.setEnabled(false);
1279 // Set the third-party cookies icon according to the theme.
1280 if (MainWebViewActivity.darkTheme) {
1281 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_ghosted_dark));
1283 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_ghosted_light));
1288 // Set the third-party cookies switch listener.
1289 thirdPartyCookiesEnabledSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1292 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_warning));
1294 // Update the third-party cookies icon according to the theme.
1295 if (MainWebViewActivity.darkTheme) {
1296 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_dark));
1298 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_light));
1303 // Set the DOM Storage switch listener.
1304 domStorageEnabledSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1307 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_enabled));
1309 // Set the icon according to the theme.
1310 if (MainWebViewActivity.darkTheme) {
1311 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_dark));
1313 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_light));
1318 // Set the form data switch listener. It can be removed once the minimum API >= 26.
1319 if (Build.VERSION.SDK_INT < 26) {
1320 formDataEnabledSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1323 formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_enabled));
1325 // Set the icon according to the theme.
1326 if (MainWebViewActivity.darkTheme) {
1327 formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_disabled_dark));
1329 formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_disabled_light));
1335 // Set the EasyList switch listener.
1336 easyListSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1338 if (isChecked) { // EasyList is on.
1339 // Set the icon according to the theme.
1340 if (MainWebViewActivity.darkTheme) {
1341 easyListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_enabled_dark));
1343 easyListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_enabled_light));
1345 } else { // EasyList is off.
1346 // Set the icon according to the theme.
1347 if (MainWebViewActivity.darkTheme) {
1348 easyListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_disabled_dark));
1350 easyListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_disabled_light));
1355 // Set the EasyPrivacy switch listener.
1356 easyPrivacySwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1358 if (isChecked) { // EasyPrivacy is on.
1359 // Set the icon according to the theme.
1360 if (MainWebViewActivity.darkTheme) {
1361 easyPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_enabled_dark));
1363 easyPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_enabled_light));
1365 } else { // EasyPrivacy is off.
1366 // Set the icon according to the theme.
1367 if (MainWebViewActivity.darkTheme) {
1368 easyPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_disabled_dark));
1370 easyPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_disabled_light));
1375 // Set the Fanboy's Annoyance List switch listener.
1376 fanboysAnnoyanceListSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1377 // Update the icon and Fanboy's Social Blocking List.
1378 if (isChecked) { // Fanboy's Annoyance List is on.
1379 // Set the icon according to the theme.
1380 if (MainWebViewActivity.darkTheme) {
1381 fanboysAnnoyanceListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_dark));
1383 fanboysAnnoyanceListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_light));
1386 // Disable the Fanboy's Social Blocking List switch.
1387 fanboysSocialBlockingListSwitch.setEnabled(false);
1389 // Update the Fanboy's Social Blocking List icon according to the theme.
1390 if (MainWebViewActivity.darkTheme) {
1391 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_ghosted_dark));
1393 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_ghosted_light));
1395 } else { // Fanboy's Annoyance List is off.
1396 // Set the icon according to the theme.
1397 if (MainWebViewActivity.darkTheme) {
1398 fanboysAnnoyanceListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_dark));
1400 fanboysAnnoyanceListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_light));
1403 // Enable the Fanboy's Social Blocking List switch.
1404 fanboysSocialBlockingListSwitch.setEnabled(true);
1406 // Update the Fanboy's Social Blocking List icon.
1407 if (fanboysSocialBlockingListSwitch.isChecked()) { // Fanboy's Social Blocking List is on.
1408 // Update the icon according to the theme.
1409 if (MainWebViewActivity.darkTheme) {
1410 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_dark));
1412 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_light));
1414 } else { // Fanboy's Social Blocking List is off.
1415 // Update the icon according to the theme.
1416 if (MainWebViewActivity.darkTheme) {
1417 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_dark));
1419 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_light));
1426 // Set the Fanboy's Social Blocking List switch listener.
1427 fanboysSocialBlockingListSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1429 if (isChecked) { // Fanboy's Social Blocking List is on.
1430 // Set the icon according to the theme.
1431 if (MainWebViewActivity.darkTheme) {
1432 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_dark));
1434 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_light));
1436 } else { // Fanboy's Social Blocking List is off.
1437 // Set the icon according to the theme.
1438 if (MainWebViewActivity.darkTheme) {
1439 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_dark));
1441 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_light));
1446 // Set the UltraPrivacy switch listener.
1447 ultraPrivacySwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1449 if (isChecked) { // UltraPrivacy is on.
1450 // Set the icon according to the theme.
1451 if (MainWebViewActivity.darkTheme) {
1452 ultraPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_enabled_dark));
1454 ultraPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_enabled_light));
1456 } else { // UltraPrivacy is off.
1457 // Set the icon according to the theme.
1458 if (MainWebViewActivity.darkTheme) {
1459 ultraPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_disabled_dark));
1461 ultraPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_disabled_light));
1466 // Set the block all third-party requests switch listener.
1467 blockAllThirdPartyRequestsSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1469 if (isChecked) { // Blocking all third-party requests is on.
1470 // Set the icon according to the theme.
1471 if (MainWebViewActivity.darkTheme) {
1472 blockAllThirdPartyRequestsImageView.setImageDrawable(resources.getDrawable(R.drawable.block_all_third_party_requests_enabled_dark));
1474 blockAllThirdPartyRequestsImageView.setImageDrawable(resources.getDrawable(R.drawable.block_all_third_party_requests_enabled_light));
1476 } else { // Blocking all third-party requests is off.
1477 // Set the icon according to the theme.
1478 if (MainWebViewActivity.darkTheme) {
1479 blockAllThirdPartyRequestsImageView.setImageDrawable(resources.getDrawable(R.drawable.block_all_third_party_requests_disabled_dark));
1481 blockAllThirdPartyRequestsImageView.setImageDrawable(resources.getDrawable(R.drawable.block_all_third_party_requests_disabled_light));
1486 // Set the user agent spinner listener.
1487 userAgentSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1489 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1490 // Set the new user agent.
1492 case MainWebViewActivity.DOMAINS_SYSTEM_DEFAULT_USER_AGENT:
1493 // Show the user agent TextView.
1494 userAgentTextView.setVisibility(View.VISIBLE);
1496 // Hide the custom user agent EditText.
1497 customUserAgentEditText.setVisibility(View.GONE);
1499 // Set the user text.
1500 switch (defaultUserAgentArrayPosition) {
1501 case MainWebViewActivity.UNRECOGNIZED_USER_AGENT: // The default user agent name is not on the canonical list.
1502 // This is probably because it was set in an older version of Privacy Browser before the switch to persistent user agent names.
1503 userAgentTextView.setText(defaultUserAgentName);
1506 case MainWebViewActivity.SETTINGS_WEBVIEW_DEFAULT_USER_AGENT:
1507 // Display the `WebView` default user agent.
1508 userAgentTextView.setText(webViewDefaultUserAgentString);
1511 case MainWebViewActivity.SETTINGS_CUSTOM_USER_AGENT:
1512 // Display the custom user agent.
1513 userAgentTextView.setText(defaultCustomUserAgentString);
1517 // Get the user agent string from the user agent data array.
1518 userAgentTextView.setText(userAgentDataArray[defaultUserAgentArrayPosition]);
1522 case MainWebViewActivity.DOMAINS_WEBVIEW_DEFAULT_USER_AGENT:
1523 // Show the user agent TextView and set the text.
1524 userAgentTextView.setVisibility(View.VISIBLE);
1525 userAgentTextView.setText(webViewDefaultUserAgentString);
1527 // Hide the custom user agent EditTex.
1528 customUserAgentEditText.setVisibility(View.GONE);
1531 case MainWebViewActivity.DOMAINS_CUSTOM_USER_AGENT:
1532 // Hide the user agent TextView.
1533 userAgentTextView.setVisibility(View.GONE);
1535 // Show the custom user agent EditText and set the current user agent name as the text.
1536 customUserAgentEditText.setVisibility(View.VISIBLE);
1537 customUserAgentEditText.setText(currentUserAgentName);
1541 // 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.
1542 userAgentTextView.setVisibility(View.VISIBLE);
1543 userAgentTextView.setText(userAgentDataArray[position - 1]);
1545 // Hide `customUserAgentEditText`.
1546 customUserAgentEditText.setVisibility(View.GONE);
1551 public void onNothingSelected(AdapterView<?> parent) {
1556 // Set the font size spinner listener.
1557 fontSizeSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1559 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1560 // Update the display options for `fontSizeTextView`.
1561 if (position == 0) { // System default font size has been selected. Display `fontSizeTextView`.
1562 fontSizeTextView.setVisibility(View.VISIBLE);
1563 } else { // A custom font size has been selected. Hide `fontSizeTextView`.
1564 fontSizeTextView.setVisibility(View.GONE);
1569 public void onNothingSelected(AdapterView<?> parent) {
1574 // Set the swipe to refresh spinner listener.
1575 swipeToRefreshSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1577 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1578 // 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.
1580 case DomainsDatabaseHelper.SWIPE_TO_REFRESH_SYSTEM_DEFAULT:
1581 if (defaultSwipeToRefresh) { // Swipe to refresh enabled by default.
1582 // Set the icon according to the theme.
1583 if (MainWebViewActivity.darkTheme) {
1584 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_enabled_dark));
1586 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_enabled_light));
1588 } else { // Swipe to refresh disabled by default.
1589 // Set the icon according to the theme.
1590 if (MainWebViewActivity.darkTheme) {
1591 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_disabled_dark));
1593 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_disabled_light));
1597 // Show the swipe to refresh TextView.
1598 swipeToRefreshTextView.setVisibility(View.VISIBLE);
1601 case DomainsDatabaseHelper.SWIPE_TO_REFRESH_ENABLED:
1602 // Set the icon according to the theme.
1603 if (MainWebViewActivity.darkTheme) {
1604 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_enabled_dark));
1606 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_enabled_light));
1609 // Hide the swipe to refresh TextView.
1610 swipeToRefreshTextView.setVisibility(View.GONE);
1613 case DomainsDatabaseHelper.SWIPE_TO_REFRESH_DISABLED:
1614 // Set the icon according to the theme.
1615 if (MainWebViewActivity.darkTheme) {
1616 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_disabled_dark));
1618 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_disabled_light));
1621 // Hide the swipe to refresh TextView.
1622 swipeToRefreshTextView.setVisibility(View.GONE);
1627 public void onNothingSelected(AdapterView<?> parent) {
1632 // Set the night mode spinner listener.
1633 nightModeSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1635 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1636 // 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.
1638 case DomainsDatabaseHelper.NIGHT_MODE_SYSTEM_DEFAULT:
1639 if (defaultNightMode) { // Night mode enabled by default.
1640 // Set the icon according to the theme.
1641 if (MainWebViewActivity.darkTheme) {
1642 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_dark));
1644 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_light));
1646 } else { // Night mode disabled by default.
1647 // Set the icon according to the theme.
1648 if (MainWebViewActivity.darkTheme) {
1649 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_dark));
1651 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_light));
1655 // Show the night mode TextView.
1656 nightModeTextView.setVisibility(View.VISIBLE);
1659 case DomainsDatabaseHelper.NIGHT_MODE_ENABLED:
1660 // Set the icon according to the theme.
1661 if (MainWebViewActivity.darkTheme) {
1662 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_dark));
1664 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_light));
1667 // Hide `nightModeTextView`.
1668 nightModeTextView.setVisibility(View.GONE);
1671 case DomainsDatabaseHelper.NIGHT_MODE_DISABLED:
1672 // Set the icon according to the theme.
1673 if (MainWebViewActivity.darkTheme) {
1674 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_dark));
1676 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_light));
1679 // Hide `nightModeTextView`.
1680 nightModeTextView.setVisibility(View.GONE);
1684 // Create a `boolean` to store the current night mode setting.
1685 boolean currentNightModeEnabled = (position == DomainsDatabaseHelper.NIGHT_MODE_ENABLED) || ((position == DomainsDatabaseHelper.NIGHT_MODE_SYSTEM_DEFAULT) && defaultNightMode);
1687 // Disable the JavaScript `Switch` if night mode is enabled.
1688 if (currentNightModeEnabled) {
1689 javaScriptEnabledSwitch.setEnabled(false);
1691 javaScriptEnabledSwitch.setEnabled(true);
1694 // Update the JavaScript icon.
1695 if ((javaScriptEnabledInt == 1) || currentNightModeEnabled) {
1696 javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.javascript_enabled));
1698 javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.privacy_mode));
1701 // Update the DOM storage status.
1702 if ((javaScriptEnabledInt == 1) || currentNightModeEnabled) { // JavaScript is enabled.
1703 // Enable the DOM storage `Switch`.
1704 domStorageEnabledSwitch.setEnabled(true);
1706 // Set the DOM storage status. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
1707 if (domStorageEnabledInt == 1) { // Both JavaScript and DOM storage are enabled.
1708 domStorageEnabledSwitch.setChecked(true);
1709 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_enabled));
1710 } else { // JavaScript is enabled but DOM storage is disabled.
1711 // Set the DOM storage switch to off.
1712 domStorageEnabledSwitch.setChecked(false);
1714 // Set the icon according to the theme.
1715 if (MainWebViewActivity.darkTheme) {
1716 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_dark));
1718 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_light));
1721 } else { // JavaScript is disabled.
1722 // Disable the DOM storage `Switch`.
1723 domStorageEnabledSwitch.setEnabled(false);
1725 // Set the checked status of DOM storage.
1726 if (domStorageEnabledInt == 1) { // DOM storage is enabled but JavaScript is disabled.
1727 domStorageEnabledSwitch.setChecked(true);
1728 } else { // Both JavaScript and DOM storage are disabled.
1729 domStorageEnabledSwitch.setChecked(false);
1732 // Set the icon according to the theme.
1733 if (MainWebViewActivity.darkTheme) {
1734 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_dark));
1736 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_light));
1742 public void onNothingSelected(AdapterView<?> parent) {
1747 // Set the display webpage images spinner listener.
1748 displayWebpageImagesSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1750 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1751 // Update the icon and the visibility of `displayImagesTextView`.
1753 case DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_SYSTEM_DEFAULT:
1754 if (defaultDisplayWebpageImages) {
1755 // Set the icon according to the theme.
1756 if (MainWebViewActivity.darkTheme) {
1757 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_dark));
1759 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_light));
1762 // Set the icon according to the theme.
1763 if (MainWebViewActivity.darkTheme) {
1764 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_dark));
1766 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_light));
1770 // Show `displayImagesTextView`.
1771 displayImagesTextView.setVisibility(View.VISIBLE);
1774 case DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_ENABLED:
1775 // Set the icon according to the theme.
1776 if (MainWebViewActivity.darkTheme) {
1777 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_dark));
1779 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_light));
1782 // Hide `displayImagesTextView`.
1783 displayImagesTextView.setVisibility(View.GONE);
1786 case DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_DISABLED:
1787 // Set the icon according to the theme.
1788 if (MainWebViewActivity.darkTheme) {
1789 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_dark));
1791 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_light));
1794 // Hide `displayImagesTextView`.
1795 displayImagesTextView.setVisibility(View.GONE);
1801 public void onNothingSelected(AdapterView<?> parent) {
1806 // Set the pinned SSL certificate switch listener.
1807 pinnedSslCertificateSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1809 if (isChecked) { // SSL certificate pinning is enabled.
1810 // Set the icon according to the theme.
1811 if (MainWebViewActivity.darkTheme) {
1812 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_dark));
1814 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_light));
1817 // Update the visibility of the saved SSL certificate.
1818 if (savedSslCertificateIssuedToCNameString == null) {
1819 savedSslCertificateCardView.setVisibility(View.GONE);
1821 savedSslCertificateCardView.setVisibility(View.VISIBLE);
1824 // Update the visibility of the current website SSL certificate.
1825 if (currentWebsiteSslCertificate == null) {
1826 // Hide the SSL certificate.
1827 currentWebsiteCertificateCardView.setVisibility(View.GONE);
1829 // Show the instruction.
1830 noCurrentWebsiteCertificateTextView.setVisibility(View.VISIBLE);
1832 // Show the SSL certificate.
1833 currentWebsiteCertificateCardView.setVisibility(View.VISIBLE);
1835 // Hide the instruction.
1836 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
1839 // Set the status of the radio buttons.
1840 if (savedSslCertificateCardView.getVisibility() == View.VISIBLE) { // The saved SSL certificate is displayed.
1841 // Check the saved SSL certificate radio button.
1842 savedSslCertificateRadioButton.setChecked(true);
1844 // Uncheck the current website SSL certificate radio button.
1845 currentWebsiteCertificateRadioButton.setChecked(false);
1847 // Set the background of the saved SSL certificate linear layout to be transparent.
1848 savedSslCertificateLinearLayout.setBackgroundResource(R.color.transparent);
1850 // Darken the background of the current website SSL certificate linear layout according to the theme.
1851 if (MainWebViewActivity.darkTheme) {
1852 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1854 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1857 // Scroll to the current website SSL certificate card.
1858 savedSslCertificateCardView.getParent().requestChildFocus(savedSslCertificateCardView, savedSslCertificateCardView);
1859 } else if (currentWebsiteCertificateCardView.getVisibility() == View.VISIBLE) { // The saved SSL certificate is hidden but the current website SSL certificate is visible.
1860 // Check the current website SSL certificate radio button.
1861 currentWebsiteCertificateRadioButton.setChecked(true);
1863 // Uncheck the saved SSL certificate radio button.
1864 savedSslCertificateRadioButton.setChecked(false);
1866 // Set the background of the current website SSL certificate linear layout to be transparent.
1867 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.transparent);
1869 // Darken the background of the saved SSL certificate linear layout according to the theme.
1870 if (MainWebViewActivity.darkTheme) {
1871 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1873 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1876 // Scroll to the current website SSL certificate card.
1877 currentWebsiteCertificateCardView.getParent().requestChildFocus(currentWebsiteCertificateCardView, currentWebsiteCertificateCardView);
1878 } else { // Neither SSL certificate is visible.
1879 // Uncheck both radio buttons.
1880 savedSslCertificateRadioButton.setChecked(false);
1881 currentWebsiteCertificateRadioButton.setChecked(false);
1883 // Scroll to the current website SSL certificate card.
1884 noCurrentWebsiteCertificateTextView.getParent().requestChildFocus(noCurrentWebsiteCertificateTextView, noCurrentWebsiteCertificateTextView);
1886 } else { // SSL certificate pinning is disabled.
1887 // Set the icon according to the theme.
1888 if (MainWebViewActivity.darkTheme) {
1889 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_dark));
1891 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_light));
1894 // Hide the SSl certificates and instructions.
1895 savedSslCertificateCardView.setVisibility(View.GONE);
1896 currentWebsiteCertificateCardView.setVisibility(View.GONE);
1897 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
1899 // Uncheck the radio buttons.
1900 savedSslCertificateRadioButton.setChecked(false);
1901 currentWebsiteCertificateRadioButton.setChecked(false);
1905 savedSslCertificateCardView.setOnClickListener((View view) -> {
1906 // Check the saved SSL certificate radio button.
1907 savedSslCertificateRadioButton.setChecked(true);
1909 // Uncheck the current website SSL certificate radio button.
1910 currentWebsiteCertificateRadioButton.setChecked(false);
1912 // Set the background of the saved SSL certificate linear layout to be transparent.
1913 savedSslCertificateLinearLayout.setBackgroundResource(R.color.transparent);
1915 // Darken the background of the current website SSL certificate linear layout according to the theme.
1916 if (MainWebViewActivity.darkTheme) {
1917 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1919 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1923 savedSslCertificateRadioButton.setOnClickListener((View view) -> {
1924 // Check the saved SSL certificate radio button.
1925 savedSslCertificateRadioButton.setChecked(true);
1927 // Uncheck the current website SSL certificate radio button.
1928 currentWebsiteCertificateRadioButton.setChecked(false);
1930 // Set the background of the saved SSL certificate linear layout to be transparent.
1931 savedSslCertificateLinearLayout.setBackgroundResource(R.color.transparent);
1933 // Darken the background of the current website SSL certificate linear layout according to the theme.
1934 if (MainWebViewActivity.darkTheme) {
1935 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1937 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1941 currentWebsiteCertificateCardView.setOnClickListener((View view) -> {
1942 // Check the current website SSL certificate radio button.
1943 currentWebsiteCertificateRadioButton.setChecked(true);
1945 // Uncheck the saved SSL certificate radio button.
1946 savedSslCertificateRadioButton.setChecked(false);
1948 // Set the background of the current website SSL certificate linear layout to be transparent.
1949 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.transparent);
1951 // Darken the background of the saved SSL certificate linear layout according to the theme.
1952 if (MainWebViewActivity.darkTheme) {
1953 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1955 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1959 currentWebsiteCertificateRadioButton.setOnClickListener((View view) -> {
1960 // Check the current website SSL certificate radio button.
1961 currentWebsiteCertificateRadioButton.setChecked(true);
1963 // Uncheck the saved SSL certificate radio button.
1964 savedSslCertificateRadioButton.setChecked(false);
1966 // Set the background of the current website SSL certificate linear layout to be transparent.
1967 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.transparent);
1969 // Darken the background of the saved SSL certificate linear layout according to the theme.
1970 if (MainWebViewActivity.darkTheme) {
1971 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1973 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1977 // Set the pinned IP addresses switch listener.
1978 pinnedIpAddressesSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1980 if (isChecked) { // IP addresses pinning is enabled.
1981 // Set the icon according to the theme.
1982 if (MainWebViewActivity.darkTheme) {
1983 pinnedIpAddressesImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_dark));
1985 pinnedIpAddressesImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_light));
1988 // Update the visibility of the saved IP addresses card view.
1989 if (savedIpAddresses == null) { // There are no saved IP addresses.
1990 savedIpAddressesCardView.setVisibility(View.GONE);
1991 } else { // There are saved IP addresses.
1992 savedIpAddressesCardView.setVisibility(View.VISIBLE);
1995 // Show the current IP addresses card view.
1996 currentIpAddressesCardView.setVisibility(View.VISIBLE);
1998 // Set the status of the radio buttons.
1999 if (savedIpAddressesCardView.getVisibility() == View.VISIBLE) { // The saved IP addresses are visible.
2000 // Check the saved IP addresses radio button.
2001 savedIpAddressesRadioButton.setChecked(true);
2003 // Uncheck the current IP addresses radio button.
2004 currentIpAddressesRadioButton.setChecked(false);
2006 // Set the background of the saved IP addresses linear layout to be transparent.
2007 savedSslCertificateLinearLayout.setBackgroundResource(R.color.transparent);
2009 // Darken the background of the current IP addresses linear layout according to the theme.
2010 if (MainWebViewActivity.darkTheme) {
2011 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2013 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2015 } else { // The saved IP addresses are not visible.
2016 // Check the current IP addresses radio button.
2017 currentIpAddressesRadioButton.setChecked(true);
2019 // Uncheck the saved IP addresses radio button.
2020 savedIpAddressesRadioButton.setChecked(false);
2022 // Set the background of the current IP addresses linear layout to be transparent.
2023 currentIpAddressesLinearLayout.setBackgroundResource(R.color.transparent);
2025 // Darken the background of the saved IP addresses linear layout according to the theme.
2026 if (MainWebViewActivity.darkTheme) {
2027 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2029 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2033 // Scroll to the bottom of the card views.
2034 currentIpAddressesCardView.getParent().requestChildFocus(currentIpAddressesCardView, currentIpAddressesCardView);
2035 } else { // IP addresses pinning is disabled.
2036 // Set the icon according to the theme.
2037 if (MainWebViewActivity.darkTheme) {
2038 pinnedIpAddressesImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_dark));
2040 pinnedIpAddressesImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_light));
2043 // Hide the IP addresses card views.
2044 savedIpAddressesCardView.setVisibility(View.GONE);
2045 currentIpAddressesCardView.setVisibility(View.GONE);
2047 // Uncheck the radio buttons.
2048 savedIpAddressesRadioButton.setChecked(false);
2049 currentIpAddressesRadioButton.setChecked(false);
2053 savedIpAddressesCardView.setOnClickListener((View view) -> {
2054 // Check the saved IP addresses radio button.
2055 savedIpAddressesRadioButton.setChecked(true);
2057 // Uncheck the current website IP addresses radio button.
2058 currentIpAddressesRadioButton.setChecked(false);
2060 // Set the background of the saved IP addresses linear layout to be transparent.
2061 savedIpAddressesLinearLayout.setBackgroundResource(R.color.transparent);
2063 // Darken the background of the current IP addresses linear layout according to the theme.
2064 if (MainWebViewActivity.darkTheme) {
2065 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2067 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2071 savedIpAddressesRadioButton.setOnClickListener((View view) -> {
2072 // Check the saved IP addresses radio button.
2073 savedIpAddressesRadioButton.setChecked(true);
2075 // Uncheck the current website IP addresses radio button.
2076 currentIpAddressesRadioButton.setChecked(false);
2078 // Set the background of the saved IP addresses linear layout to be transparent.
2079 savedIpAddressesLinearLayout.setBackgroundResource(R.color.transparent);
2081 // Darken the background of the current IP addresses linear layout according to the theme.
2082 if (MainWebViewActivity.darkTheme) {
2083 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2085 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2089 currentIpAddressesCardView.setOnClickListener((View view) -> {
2090 // Check the current IP addresses radio button.
2091 currentIpAddressesRadioButton.setChecked(true);
2093 // Uncheck the saved IP addresses radio button.
2094 savedIpAddressesRadioButton.setChecked(false);
2096 // Set the background of the current IP addresses linear layout to be transparent.
2097 currentIpAddressesLinearLayout.setBackgroundResource(R.color.transparent);
2099 // Darken the background of the saved IP addresses linear layout according to the theme.
2100 if (MainWebViewActivity.darkTheme) {
2101 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2103 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2107 currentIpAddressesRadioButton.setOnClickListener((View view) -> {
2108 // Check the current IP addresses radio button.
2109 currentIpAddressesRadioButton.setChecked(true);
2111 // Uncheck the saved IP addresses radio button.
2112 savedIpAddressesRadioButton.setChecked(false);
2114 // Set the background of the current IP addresses linear layout to be transparent.
2115 currentIpAddressesLinearLayout.setBackgroundResource(R.color.transparent);
2117 // Darken the background of the saved IP addresses linear layout according to the theme.
2118 if (MainWebViewActivity.darkTheme) {
2119 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2121 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2125 return domainSettingsView;
2128 private boolean checkDomainNameAgainstCertificate(String domainName, String certificateCommonName) {
2129 // Initialize `domainNamesMatch`.
2130 boolean domainNamesMatch = false;
2132 // Check various wildcard permutations if `domainName` and `certificateCommonName` are not empty.
2133 // `noinspection ConstantCondition` removes Android Studio's incorrect lint warning that `domainName` can never be `null`.
2134 //noinspection ConstantConditions
2135 if ((domainName != null) && (certificateCommonName != null)) {
2136 // Check if the domains match.
2137 if (domainName.equals(certificateCommonName)) {
2138 domainNamesMatch = true;
2141 // If `domainName` starts with a wildcard, check the base domain against all the subdomains of `certificateCommonName`.
2142 if (!domainNamesMatch && domainName.startsWith("*.") && (domainName.length() > 2)) {
2143 // Remove the initial `*.`.
2144 String baseDomainName = domainName.substring(2);
2146 // Setup a copy of `certificateCommonName` to test subdomains.
2147 String certificateCommonNameSubdomain = certificateCommonName;
2149 // Check all the subdomains in `certificateCommonNameSubdomain` against `baseDomainName`.
2150 while (!domainNamesMatch && certificateCommonNameSubdomain.contains(".")) { // Stop checking if we know that `domainNamesMatch` is `true` or if we run out of `.`.
2151 // Test the `certificateCommonNameSubdomain` against `baseDomainName`.
2152 if (certificateCommonNameSubdomain.equals(baseDomainName)) {
2153 domainNamesMatch = true;
2156 // Strip out the lowest subdomain of `certificateCommonNameSubdomain`.
2158 certificateCommonNameSubdomain = certificateCommonNameSubdomain.substring(certificateCommonNameSubdomain.indexOf(".") + 1);
2159 } catch (IndexOutOfBoundsException e) { // `certificateCommonNameSubdomain` ends with `.`.
2160 certificateCommonNameSubdomain = "";
2165 // If `certificateCommonName` starts with a wildcard, check the base common name against all the subdomains of `domainName`.
2166 if (!domainNamesMatch && certificateCommonName.startsWith("*.") && (certificateCommonName.length() > 2)) {
2167 // Remove the initial `*.`.
2168 String baseCertificateCommonName = certificateCommonName.substring(2);
2170 // Setup a copy of `domainName` to test subdomains.
2171 String domainNameSubdomain = domainName;
2173 // Check all the subdomains in `domainNameSubdomain` against `baseCertificateCommonName`.
2174 while (!domainNamesMatch && domainNameSubdomain.contains(".") && (domainNameSubdomain.length() > 2)) {
2175 // Test the `domainNameSubdomain` against `baseCertificateCommonName`.
2176 if (domainNameSubdomain.equals(baseCertificateCommonName)) {
2177 domainNamesMatch = true;
2180 // Strip out the lowest subdomain of `domainNameSubdomain`.
2182 domainNameSubdomain = domainNameSubdomain.substring(domainNameSubdomain.indexOf(".") + 1);
2183 } catch (IndexOutOfBoundsException e) { // `domainNameSubdomain` ends with `.`.
2184 domainNameSubdomain = "";
2189 // If both names start with a wildcard, check if the root of one contains the root of the other.
2190 if (!domainNamesMatch && domainName.startsWith("*.") && (domainName.length() > 2) && certificateCommonName.startsWith("*.") && (certificateCommonName.length() > 2)) {
2191 // Remove the wildcards.
2192 String rootDomainName = domainName.substring(2);
2193 String rootCertificateCommonName = certificateCommonName.substring(2);
2195 // Check if one name ends with the contents of the other. If so, there will be overlap in the their wildcard subdomains.
2196 if (rootDomainName.endsWith(rootCertificateCommonName) || rootCertificateCommonName.endsWith(rootDomainName)) {
2197 domainNamesMatch = true;
2202 return domainNamesMatch;