2 * Copyright © 2017-2018 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 // We have to use `android.support.v4.app.Fragment` until minimum API >= 23. Otherwise we cannot call `getContext()`.
31 import android.preference.PreferenceManager;
32 import android.support.annotation.NonNull;
33 import android.support.v4.app.Fragment;
34 import android.text.Editable;
35 import android.text.SpannableStringBuilder;
36 import android.text.Spanned;
37 import android.text.TextWatcher;
38 import android.text.style.ForegroundColorSpan;
39 import android.view.LayoutInflater;
40 import android.view.View;
41 import android.view.ViewGroup;
42 import android.webkit.WebView;
43 import android.widget.AdapterView;
44 import android.widget.ArrayAdapter;
45 import android.widget.CompoundButton;
46 import android.widget.EditText;
47 import android.widget.ImageView;
48 import android.widget.LinearLayout;
49 import android.widget.RadioButton;
50 import android.widget.Spinner;
51 import android.widget.Switch;
52 import android.widget.TextView;
54 import com.stoutner.privacybrowser.R;
55 import com.stoutner.privacybrowser.activities.MainWebViewActivity;
56 import com.stoutner.privacybrowser.helpers.DomainsDatabaseHelper;
58 import java.text.DateFormat;
59 import java.util.Calendar;
60 import java.util.Date;
62 public class DomainSettingsFragment extends Fragment {
63 // `DATABASE_ID` is used by activities calling this fragment.
64 public static final String DATABASE_ID = "database_id";
66 // `databaseId` is public static so it can be accessed from `DomainsActivity`. It is also used in `onCreate()` and `onCreateView()`.
67 public static int databaseId;
70 public void onCreate(Bundle savedInstanceState) {
71 super.onCreate(savedInstanceState);
73 // Remove the lint warning that `getArguments` might be null.
74 assert getArguments() != null;
76 // Store the database id in `databaseId`.
77 databaseId = getArguments().getInt(DATABASE_ID);
80 // The deprecated `getDrawable()` must be used until the minimum API >= 21.
81 @SuppressWarnings("deprecation")
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", "Privacy Browser");
96 final String defaultCustomUserAgentString = sharedPreferences.getString("custom_user_agent", "PrivacyBrowser/1.0");
97 String defaultFontSizeString = sharedPreferences.getString("default_font_size", "100");
98 final boolean defaultDisplayWebpageImagesBoolean = sharedPreferences.getBoolean("display_website_images", true);
99 final boolean defaultNightModeBoolean = sharedPreferences.getBoolean("night_mode", false);
101 // Get handles for the views in the fragment.
102 final EditText domainNameEditText = domainSettingsView.findViewById(R.id.domain_settings_name_edittext);
103 final Switch javaScriptEnabledSwitch = domainSettingsView.findViewById(R.id.domain_settings_javascript_switch);
104 final ImageView javaScriptImageView = domainSettingsView.findViewById(R.id.domain_settings_javascript_imageview);
105 Switch firstPartyCookiesEnabledSwitch = domainSettingsView.findViewById(R.id.domain_settings_first_party_cookies_switch);
106 final ImageView firstPartyCookiesImageView = domainSettingsView.findViewById(R.id.domain_settings_first_party_cookies_imageview);
107 LinearLayout thirdPartyCookiesLinearLayout = domainSettingsView.findViewById(R.id.domain_settings_third_party_cookies_linearlayout);
108 final Switch thirdPartyCookiesEnabledSwitch = domainSettingsView.findViewById(R.id.domain_settings_third_party_cookies_switch);
109 final ImageView thirdPartyCookiesImageView = domainSettingsView.findViewById(R.id.domain_settings_third_party_cookies_imageview);
110 final Switch domStorageEnabledSwitch = domainSettingsView.findViewById(R.id.domain_settings_dom_storage_switch);
111 final ImageView domStorageImageView = domainSettingsView.findViewById(R.id.domain_settings_dom_storage_imageview);
112 Switch formDataEnabledSwitch = domainSettingsView.findViewById(R.id.domain_settings_form_data_switch);
113 final ImageView formDataImageView = domainSettingsView.findViewById(R.id.domain_settings_form_data_imageview);
114 Switch easyListSwitch = domainSettingsView.findViewById(R.id.domain_settings_easylist_switch);
115 ImageView easyListImageView = domainSettingsView.findViewById(R.id.domain_settings_easylist_imageview);
116 Switch easyPrivacySwitch = domainSettingsView.findViewById(R.id.domain_settings_easyprivacy_switch);
117 ImageView easyPrivacyImageView = domainSettingsView.findViewById(R.id.domain_settings_easyprivacy_imageview);
118 Switch fanboysAnnoyanceListSwitch = domainSettingsView.findViewById(R.id.domain_settings_fanboys_annoyance_list_switch);
119 ImageView fanboysAnnoyanceListImageView = domainSettingsView.findViewById(R.id.domain_settings_fanboys_annoyance_list_imageview);
120 Switch fanboysSocialBlockingListSwitch = domainSettingsView.findViewById(R.id.domain_settings_fanboys_social_blocking_list_switch);
121 ImageView fanboysSocialBlockingListImageView = domainSettingsView.findViewById(R.id.domain_settings_fanboys_social_blocking_list_imageview);
122 final Spinner userAgentSpinner = domainSettingsView.findViewById(R.id.domain_settings_user_agent_spinner);
123 final TextView userAgentTextView = domainSettingsView.findViewById(R.id.domain_settings_user_agent_textview);
124 final EditText customUserAgentEditText = domainSettingsView.findViewById(R.id.domain_settings_custom_user_agent_edittext);
125 final Spinner fontSizeSpinner = domainSettingsView.findViewById(R.id.domain_settings_font_size_spinner);
126 final TextView fontSizeTextView = domainSettingsView.findViewById(R.id.domain_settings_font_size_textview);
127 final ImageView displayWebpageImagesImageView = domainSettingsView.findViewById(R.id.domain_settings_display_webpage_images_imageview);
128 final Spinner displayWebpageImagesSpinner = domainSettingsView.findViewById(R.id.domain_settings_display_webpage_images_spinner);
129 final TextView displayImagesTextView = domainSettingsView.findViewById(R.id.domain_settings_display_webpage_images_textview);
130 final ImageView nightModeImageView = domainSettingsView.findViewById(R.id.domain_settings_night_mode_imageview);
131 final Spinner nightModeSpinner = domainSettingsView.findViewById(R.id.domain_settings_night_mode_spinner);
132 final TextView nightModeTextView = domainSettingsView.findViewById(R.id.domain_settings_night_mode_textview);
133 final ImageView pinnedSslCertificateImageView = domainSettingsView.findViewById(R.id.domain_settings_pinned_ssl_certificate_imageview);
134 Switch pinnedSslCertificateSwitch = domainSettingsView.findViewById(R.id.domain_settings_pinned_ssl_certificate_switch);
135 final LinearLayout savedSslCertificateLinearLayout = domainSettingsView.findViewById(R.id.saved_ssl_certificate_linearlayout);
136 final RadioButton savedSslCertificateRadioButton = domainSettingsView.findViewById(R.id.saved_ssl_certificate_radiobutton);
137 final TextView savedSslCertificateIssuedToCNameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_to_cname);
138 TextView savedSslCertificateIssuedToONameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_to_oname);
139 TextView savedSslCertificateIssuedToUNameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_to_uname);
140 TextView savedSslCertificateIssuedByCNameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_by_cname);
141 TextView savedSslCertificateIssuedByONameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_by_oname);
142 TextView savedSslCertificateIssuedByUNameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_by_uname);
143 TextView savedSslCertificateStartDateTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_start_date);
144 TextView savedSslCertificateEndDateTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_end_date);
145 final LinearLayout currentWebsiteCertificateLinearLayout = domainSettingsView.findViewById(R.id.current_website_certificate_linearlayout);
146 final RadioButton currentWebsiteCertificateRadioButton = domainSettingsView.findViewById(R.id.current_website_certificate_radiobutton);
147 final TextView currentWebsiteCertificateIssuedToCNameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_to_cname);
148 TextView currentWebsiteCertificateIssuedToONameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_to_oname);
149 TextView currentWebsiteCertificateIssuedToUNameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_to_uname);
150 TextView currentWebsiteCertificateIssuedByCNameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_by_cname);
151 TextView currentWebsiteCertificateIssuedByONameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_by_oname);
152 TextView currentWebsiteCertificateIssuedByUNameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_by_uname);
153 TextView currentWebsiteCertificateStartDateTextView = domainSettingsView.findViewById(R.id.current_website_certificate_start_date);
154 TextView currentWebsiteCertificateEndDateTextView = domainSettingsView.findViewById(R.id.current_website_certificate_end_date);
155 final TextView noCurrentWebsiteCertificateTextView = domainSettingsView.findViewById(R.id.no_current_website_certificate);
157 // Setup the SSL certificate labels.
158 final String cNameLabel = getString(R.string.common_name) + " ";
159 String oNameLabel = getString(R.string.organization) + " ";
160 String uNameLabel = getString(R.string.organizational_unit) + " ";
161 String startDateLabel = getString(R.string.start_date) + " ";
162 String endDateLabel = getString(R.string.end_date) + " ";
164 // Get the current website SSL certificate
165 final SslCertificate currentWebsiteSslCertificate = MainWebViewActivity.sslCertificate;
167 // Initialize the database handler. The `0` specifies the database version, but that is ignored and set instead using a constant in `DomainsDatabaseHelper`.
168 DomainsDatabaseHelper domainsDatabaseHelper = new DomainsDatabaseHelper(context, null, null, 0);
170 // Get the database `Cursor` for this ID and move it to the first row.
171 Cursor domainCursor = domainsDatabaseHelper.getCursorForId(databaseId);
172 domainCursor.moveToFirst();
174 // Save the `Cursor` entries as variables.
175 String domainNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.DOMAIN_NAME));
176 final int javaScriptEnabledInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_JAVASCRIPT));
177 int firstPartyCookiesEnabledInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FIRST_PARTY_COOKIES));
178 int thirdPartyCookiesEnabledInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_THIRD_PARTY_COOKIES));
179 final int domStorageEnabledInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_DOM_STORAGE));
180 int formDataEnabledInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FORM_DATA));
181 int easyListEnabledInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_EASYLIST));
182 int easyPrivacyEnabledInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_EASYPRIVACY));
183 int fanboysAnnoyanceListInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FANBOYS_ANNOYANCE_LIST));
184 int fanboysSocialBlockingListInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FANBOYS_SOCIAL_BLOCKING_LIST));
185 final String currentUserAgentName = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.USER_AGENT));
186 int fontSizeInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.FONT_SIZE));
187 int displayImagesInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.DISPLAY_IMAGES));
188 int nightModeInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.NIGHT_MODE));
189 int pinnedSslCertificateInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.PINNED_SSL_CERTIFICATE));
190 final String savedSslCertificateIssuedToCNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_TO_COMMON_NAME));
191 String savedSslCertificateIssuedToONameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_TO_ORGANIZATION));
192 String savedSslCertificateIssuedToUNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_TO_ORGANIZATIONAL_UNIT));
193 String savedSslCertificateIssuedByCNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_BY_COMMON_NAME));
194 String savedSslCertificateIssuedByONameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_BY_ORGANIZATION));
195 String savedSslCertificateIssuedByUNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_BY_ORGANIZATIONAL_UNIT));
197 // Initialize the saved SSL certificate date variables.
198 Date savedSslCertificateStartDate = null;
199 Date savedSslCertificateEndDate = null;
201 // Only get the saved SSL certificate dates from the cursor if they are not set to `0`.
202 if (domainCursor.getLong(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_START_DATE)) != 0) {
203 savedSslCertificateStartDate = new Date(domainCursor.getLong(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_START_DATE)));
206 if (domainCursor.getLong(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_END_DATE)) != 0) {
207 savedSslCertificateEndDate = new Date(domainCursor.getLong(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_END_DATE)));
210 // Create `ArrayAdapters` for the `Spinners`and their `entry values`.
211 ArrayAdapter<CharSequence> translatedUserAgentArrayAdapter = ArrayAdapter.createFromResource(context, R.array.translated_domain_settings_user_agent_names, R.layout.domain_settings_spinner_item);
212 ArrayAdapter<CharSequence> fontSizeArrayAdapter = ArrayAdapter.createFromResource(context, R.array.domain_settings_font_size_entries, R.layout.domain_settings_spinner_item);
213 ArrayAdapter<CharSequence> fontSizeEntryValuesArrayAdapter = ArrayAdapter.createFromResource(context, R.array.domain_settings_font_size_entry_values, R.layout.domain_settings_spinner_item);
214 final ArrayAdapter<CharSequence> displayImagesArrayAdapter = ArrayAdapter.createFromResource(context, R.array.display_webpage_images_array, R.layout.domain_settings_spinner_item);
215 ArrayAdapter<CharSequence> nightModeArrayAdapter = ArrayAdapter.createFromResource(context, R.array.night_mode_array, R.layout.domain_settings_spinner_item);
217 // Set the `DropDownViewResource` on the `Spinners`.
218 translatedUserAgentArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_item);
219 fontSizeArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_item);
220 displayImagesArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_item);
221 nightModeArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_item);
223 // Set the `ArrayAdapters` for the `Spinners`.
224 userAgentSpinner.setAdapter(translatedUserAgentArrayAdapter);
225 fontSizeSpinner.setAdapter(fontSizeArrayAdapter);
226 displayWebpageImagesSpinner.setAdapter(displayImagesArrayAdapter);
227 nightModeSpinner.setAdapter(nightModeArrayAdapter);
229 // Create a `SpannableStringBuilder` for each `TextView` that needs multiple colors of text.
230 SpannableStringBuilder savedSslCertificateIssuedToCNameStringBuilder = new SpannableStringBuilder(cNameLabel + savedSslCertificateIssuedToCNameString);
231 SpannableStringBuilder savedSslCertificateIssuedToONameStringBuilder = new SpannableStringBuilder(oNameLabel + savedSslCertificateIssuedToONameString);
232 SpannableStringBuilder savedSslCertificateIssuedToUNameStringBuilder = new SpannableStringBuilder(uNameLabel + savedSslCertificateIssuedToUNameString);
233 SpannableStringBuilder savedSslCertificateIssuedByCNameStringBuilder = new SpannableStringBuilder(cNameLabel + savedSslCertificateIssuedByCNameString);
234 SpannableStringBuilder savedSslCertificateIssuedByONameStringBuilder = new SpannableStringBuilder(oNameLabel + savedSslCertificateIssuedByONameString);
235 SpannableStringBuilder savedSslCertificateIssuedByUNameStringBuilder = new SpannableStringBuilder(uNameLabel + savedSslCertificateIssuedByUNameString);
237 // Initialize the `SpannableStringBuilders` for the SSL certificate dates.
238 SpannableStringBuilder savedSslCertificateStartDateStringBuilder;
239 SpannableStringBuilder savedSslCertificateEndDateStringBuilder;
241 // Leave the SSL certificate dates empty if they are `null`.
242 if (savedSslCertificateStartDate == null) {
243 savedSslCertificateStartDateStringBuilder = new SpannableStringBuilder(startDateLabel);
245 savedSslCertificateStartDateStringBuilder = new SpannableStringBuilder(startDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(savedSslCertificateStartDate));
248 if (savedSslCertificateEndDate == null) {
249 savedSslCertificateEndDateStringBuilder = new SpannableStringBuilder(endDateLabel);
251 savedSslCertificateEndDateStringBuilder = new SpannableStringBuilder(endDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(savedSslCertificateEndDate));
254 // Create a red `ForegroundColorSpan`. We have to use the deprecated `getColor` until API >= 23.
255 final ForegroundColorSpan redColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.red_a700));
257 // Create a blue `ForegroundColorSpan`.
258 final ForegroundColorSpan blueColorSpan;
260 // Set `blueColorSpan` according to the theme. We have to use the deprecated `getColor()` until API >= 23.
261 if (MainWebViewActivity.darkTheme) {
262 //noinspection deprecation
263 blueColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.blue_400));
265 //noinspection deprecation
266 blueColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.blue_700));
269 // Set the domain name from the the database cursor.
270 domainNameEditText.setText(domainNameString);
272 // Update the certificates' `Common Name` color when the domain name text changes.
273 domainNameEditText.addTextChangedListener(new TextWatcher() {
275 public void beforeTextChanged(CharSequence s, int start, int count, int after) {
280 public void onTextChanged(CharSequence s, int start, int before, int count) {
285 public void afterTextChanged(Editable s) {
286 // Get the new domain name.
287 String newDomainName = domainNameEditText.getText().toString();
289 // Check the saved SSL certificate against the new domain name.
290 boolean savedSslCertificateMatchesNewDomainName = checkDomainNameAgainstCertificate(newDomainName, savedSslCertificateIssuedToCNameString);
292 // Create a `SpannableStringBuilder` for the saved certificate `Common Name`.
293 SpannableStringBuilder savedSslCertificateCommonNameStringBuilder = new SpannableStringBuilder(cNameLabel + savedSslCertificateIssuedToCNameString);
295 // Format the saved certificate `Common Name` color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
296 if (savedSslCertificateMatchesNewDomainName) {
297 savedSslCertificateCommonNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), savedSslCertificateCommonNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
299 savedSslCertificateCommonNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), savedSslCertificateCommonNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
302 // Update `savedSslCertificateIssuedToCNameTextView`.
303 savedSslCertificateIssuedToCNameTextView.setText(savedSslCertificateCommonNameStringBuilder);
305 // Update the current website certificate if it exists.
306 if (currentWebsiteSslCertificate != null) {
307 // Get the current website certificate `Common Name`.
308 String currentWebsiteCertificateCommonName = currentWebsiteSslCertificate.getIssuedTo().getCName();
310 // Check the current website certificate against the new domain name.
311 boolean currentWebsiteCertificateMatchesNewDomainName = checkDomainNameAgainstCertificate(newDomainName, currentWebsiteCertificateCommonName);
313 // Create a `SpannableStringBuilder` for the current website certificate `Common Name`.
314 SpannableStringBuilder currentWebsiteCertificateCommonNameStringBuilder = new SpannableStringBuilder(cNameLabel + currentWebsiteCertificateCommonName);
316 // Format the current certificate `Common Name` color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
317 if (currentWebsiteCertificateMatchesNewDomainName) {
318 currentWebsiteCertificateCommonNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), currentWebsiteCertificateCommonNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
320 currentWebsiteCertificateCommonNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), currentWebsiteCertificateCommonNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
323 // Update `currentWebsiteCertificateIssuedToCNameTextView`.
324 currentWebsiteCertificateIssuedToCNameTextView.setText(currentWebsiteCertificateCommonNameStringBuilder);
329 // Create a `boolean` to track if night mode is enabled.
330 boolean nightModeEnabled = (nightModeInt == DomainsDatabaseHelper.NIGHT_MODE_ENABLED) || ((nightModeInt == DomainsDatabaseHelper.NIGHT_MODE_SYSTEM_DEFAULT) && defaultNightModeBoolean);
332 // Disable the JavaScript `Switch` if night mode is enabled.
333 if (nightModeEnabled) {
334 javaScriptEnabledSwitch.setEnabled(false);
336 javaScriptEnabledSwitch.setEnabled(true);
339 // Set the JavaScript icon.
340 if ((javaScriptEnabledInt == 1) || nightModeEnabled) {
341 javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.javascript_enabled));
343 javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.privacy_mode));
346 // Set the JavaScript `Switch` status.
347 if (javaScriptEnabledInt == 1) { // JavaScript is enabled.
348 javaScriptEnabledSwitch.setChecked(true);
349 } else { // JavaScript is disabled.
350 javaScriptEnabledSwitch.setChecked(false);
353 // 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.
354 if (firstPartyCookiesEnabledInt == 1) { // First-party cookies are enabled.
355 firstPartyCookiesEnabledSwitch.setChecked(true);
356 firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_enabled));
357 } else { // First-party cookies are disabled.
358 firstPartyCookiesEnabledSwitch.setChecked(false);
360 // Set the icon according to the theme.
361 if (MainWebViewActivity.darkTheme) {
362 firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_dark));
364 firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_light));
368 // Only display third-party cookies if SDK_INT >= 21.
369 if (Build.VERSION.SDK_INT >= 21) { // Third-party cookies can be configured for API >= 21.
370 // Only enable third-party-cookies if first-party cookies are enabled.
371 if (firstPartyCookiesEnabledInt == 1) { // First-party cookies are enabled.
372 // 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.
373 if (thirdPartyCookiesEnabledInt == 1) { // Both first-party and third-party cookies are enabled.
374 thirdPartyCookiesEnabledSwitch.setChecked(true);
375 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_warning));
376 } else { // First party cookies are enabled but third-party cookies are disabled.
377 thirdPartyCookiesEnabledSwitch.setChecked(false);
379 // Set the icon according to the theme.
380 if (MainWebViewActivity.darkTheme) {
381 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_dark));
383 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_light));
386 } else { // First-party cookies are disabled.
387 // Set the status of third-party cookies.
388 if (thirdPartyCookiesEnabledInt == 1) {
389 thirdPartyCookiesEnabledSwitch.setChecked(true);
391 thirdPartyCookiesEnabledSwitch.setChecked(false);
394 // Disable the third-party cookies switch.
395 thirdPartyCookiesEnabledSwitch.setEnabled(false);
397 // Set the icon according to the theme.
398 if (MainWebViewActivity.darkTheme) {
399 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_ghosted_dark));
401 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_ghosted_light));
404 } else { // Third-party cookies cannot be configured for API <= 21.
405 // Hide the `LinearLayout` for third-party cookies.
406 thirdPartyCookiesLinearLayout.setVisibility(View.GONE);
409 // Only enable DOM storage if JavaScript is enabled.
410 if ((javaScriptEnabledInt == 1) || nightModeEnabled) { // JavaScript is enabled.
411 // Enable the DOM storage `Switch`.
412 domStorageEnabledSwitch.setEnabled(true);
414 // Set the DOM storage status. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
415 if (domStorageEnabledInt == 1) { // Both JavaScript and DOM storage are enabled.
416 domStorageEnabledSwitch.setChecked(true);
417 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_enabled));
418 } else { // JavaScript is enabled but DOM storage is disabled.
419 // Set the DOM storage switch to off.
420 domStorageEnabledSwitch.setChecked(false);
422 // Set the icon according to the theme.
423 if (MainWebViewActivity.darkTheme) {
424 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_dark));
426 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_light));
429 } else { // JavaScript is disabled.
430 // Disable the DOM storage `Switch`.
431 domStorageEnabledSwitch.setEnabled(false);
433 // Set the checked status of DOM storage.
434 if (domStorageEnabledInt == 1) { // DOM storage is enabled but JavaScript is disabled.
435 domStorageEnabledSwitch.setChecked(true);
436 } else { // Both JavaScript and DOM storage are disabled.
437 domStorageEnabledSwitch.setChecked(false);
440 // Set the icon according to the theme.
441 if (MainWebViewActivity.darkTheme) {
442 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_dark));
444 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_light));
448 // Set the form data status. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
449 if (formDataEnabledInt == 1) { // Form data is on.
450 formDataEnabledSwitch.setChecked(true);
451 formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_enabled));
452 } else { // Form data is off.
453 // Turn the form data switch to off.
454 formDataEnabledSwitch.setChecked(false);
456 // Set the icon according to the theme.
457 if (MainWebViewActivity.darkTheme) {
458 formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_disabled_dark));
460 formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_disabled_light));
464 // Set the EasyList status. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
465 if (easyListEnabledInt == 1) { // EasyList is on.
466 // Turn the switch on.
467 easyListSwitch.setChecked(true);
469 // Set the icon according to the theme.
470 if (MainWebViewActivity.darkTheme) {
471 easyListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_enabled_dark));
473 easyListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_enabled_light));
475 } else { // EasyList is off.
476 // Turn the switch off.
477 easyListSwitch.setChecked(false);
479 // Set the icon according to the theme.
480 if (MainWebViewActivity.darkTheme) {
481 easyListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_disabled_dark));
483 easyListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_disabled_light));
487 // Set the EasyPrivacy status. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
488 if (easyPrivacyEnabledInt == 1) { // EasyPrivacy is on.
489 // Turn the switch on.
490 easyPrivacySwitch.setChecked(true);
492 // Set the icon according to the theme.
493 if (MainWebViewActivity.darkTheme) {
494 easyPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_enabled_dark));
496 easyPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_enabled_light));
498 } else { // EasyPrivacy is off.
499 // Turn the switch off.
500 easyPrivacySwitch.setChecked(false);
502 // Set the icon according to the theme.
503 if (MainWebViewActivity.darkTheme) {
504 easyPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_disabled_dark));
506 easyPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_disabled_light));
510 // 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.
511 if (fanboysAnnoyanceListInt == 1) { // Fanboy's Annoyance List is on.
512 // Turn the switch on.
513 fanboysAnnoyanceListSwitch.setChecked(true);
515 // Set the icon according to the theme.
516 if (MainWebViewActivity.darkTheme) {
517 fanboysAnnoyanceListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_dark));
519 fanboysAnnoyanceListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_light));
521 } else { // Fanboy's Annoyance List is off.
522 // Turn the switch off.
523 fanboysAnnoyanceListSwitch.setChecked(false);
525 // Set the icon according to the theme.
526 if (MainWebViewActivity.darkTheme) {
527 fanboysAnnoyanceListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_dark));
529 fanboysAnnoyanceListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_light));
533 // Only enable Fanboy's Social Blocking List if Fanboy's Annoyance List is off.
534 if (fanboysAnnoyanceListInt == 0) { // Fanboy's Annoyance List is on.
535 // 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.
536 if (fanboysSocialBlockingListInt == 1) { // Fanboy's Social Blocking List is on.
537 // Enable the switch and turn it on.
538 fanboysSocialBlockingListSwitch.setEnabled(true);
539 fanboysSocialBlockingListSwitch.setChecked(true);
541 // Set the icon according to the theme.
542 if (MainWebViewActivity.darkTheme) {
543 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_dark));
545 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_light));
547 } else { // Fanboy's Social Blocking List is off.
548 // Enable the switch but turn it off.
549 fanboysSocialBlockingListSwitch.setEnabled(true);
550 fanboysSocialBlockingListSwitch.setChecked(false);
552 // Set the icon according to the theme.
553 if (MainWebViewActivity.darkTheme) {
554 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_dark));
556 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_light));
559 } else { // Fanboy's Annoyance List is on.
560 // 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.
561 if (fanboysSocialBlockingListInt == 1) { // Fanboy's Social Blocking List is on.
562 // Disable the switch but turn it on.
563 fanboysSocialBlockingListSwitch.setEnabled(false);
564 fanboysSocialBlockingListSwitch.setChecked(true);
565 } else { // Fanboy's Social Blocking List is off.
566 // Disable the switch and turn it off.
567 fanboysSocialBlockingListSwitch.setEnabled(false);
568 fanboysSocialBlockingListSwitch.setChecked(false);
571 // Set the icon according to the theme.
572 if (MainWebViewActivity.darkTheme) {
573 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_ghosted_dark));
575 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_ghosted_light));
579 // Inflated a WebView to get the default user agent.
580 // `@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.
581 @SuppressLint("InflateParams") View bareWebViewLayout = inflater.inflate(R.layout.bare_webview, null, false);
582 WebView bareWebView = bareWebViewLayout.findViewById(R.id.bare_webview);
583 final String webViewDefaultUserAgentString = bareWebView.getSettings().getUserAgentString();
585 // Get a handle for the user agent array adapter. This array does not contain the `System default` entry.
586 ArrayAdapter<CharSequence> userAgentNamesArray = ArrayAdapter.createFromResource(context, R.array.user_agent_names, R.layout.domain_settings_spinner_item);
588 // Get the positions of the user agent and the default user agent.
589 int userAgentArrayPosition = userAgentNamesArray.getPosition(currentUserAgentName);
590 int defaultUserAgentArrayPosition = userAgentNamesArray.getPosition(defaultUserAgentName);
592 // Get a handle for the user agent data array. This array does not contain the `System default` entry.
593 String[] userAgentDataArray = resources.getStringArray(R.array.user_agent_data);
595 // Set the user agent text.
596 if (currentUserAgentName.equals(getString(R.string.system_default_user_agent))) { // Use the system default user agent.
597 // Set the user agent according to the system default.
598 switch (defaultUserAgentArrayPosition) {
599 case MainWebViewActivity.UNRECOGNIZED_USER_AGENT: // The default user agent name is not on the canonical list.
600 // This is probably because it was set in an older version of Privacy Browser before the switch to persistent user agent names.
601 userAgentTextView.setText(defaultUserAgentName);
604 case MainWebViewActivity.SETTINGS_WEBVIEW_DEFAULT_USER_AGENT:
605 // Display the `WebView` default user agent.
606 userAgentTextView.setText(webViewDefaultUserAgentString);
609 case MainWebViewActivity.SETTINGS_CUSTOM_USER_AGENT:
610 // Display the custom user agent.
611 userAgentTextView.setText(defaultCustomUserAgentString);
615 // Get the user agent string from the user agent data array.
616 userAgentTextView.setText(userAgentDataArray[defaultUserAgentArrayPosition]);
618 } else if (userAgentArrayPosition == MainWebViewActivity.UNRECOGNIZED_USER_AGENT) { // A custom user agent is stored in the current user agent name.
619 // Set the user agent spinner to `Custom user agent`.
620 userAgentSpinner.setSelection(MainWebViewActivity.DOMAINS_CUSTOM_USER_AGENT);
622 // Hide the user agent TextView.
623 userAgentTextView.setVisibility(View.GONE);
625 // Show the custom user agent EditText and set the current user agent name as the text.
626 customUserAgentEditText.setVisibility(View.VISIBLE);
627 customUserAgentEditText.setText(currentUserAgentName);
628 } else { // The user agent name contains one of the canonical user agents.
629 // 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.
630 userAgentSpinner.setSelection(userAgentArrayPosition + 1);
632 // Show the user agent TextView.
633 userAgentTextView.setVisibility(View.VISIBLE);
635 // Hide the custom user agent EditText.
636 customUserAgentEditText.setVisibility(View.GONE);
638 // Set the user agent text.
639 switch (userAgentArrayPosition) {
640 case MainWebViewActivity.DOMAINS_WEBVIEW_DEFAULT_USER_AGENT:
641 // Display the WebView default user agent.
642 userAgentTextView.setText(webViewDefaultUserAgentString);
646 // 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.
647 userAgentTextView.setText(userAgentDataArray[userAgentArrayPosition + 1]);
651 // Open the user agent spinner when the `TextView` is clicked.
652 userAgentTextView.setOnClickListener((View v) -> {
653 // Open the user agent spinner.
654 userAgentSpinner.performClick();
657 // Set the selected font size.
658 int fontSizeArrayPosition = fontSizeEntryValuesArrayAdapter.getPosition(String.valueOf(fontSizeInt));
659 fontSizeSpinner.setSelection(fontSizeArrayPosition);
661 // Set the default font size text.
662 int defaultFontSizeArrayPosition = fontSizeEntryValuesArrayAdapter.getPosition(defaultFontSizeString);
663 fontSizeTextView.setText(fontSizeArrayAdapter.getItem(defaultFontSizeArrayPosition));
665 // Set the display options for `fontSizeTextView`.
666 if (fontSizeArrayPosition == 0) { // System default font size is selected. Display `fontSizeTextView`.
667 fontSizeTextView.setVisibility(View.VISIBLE);
668 } else { // A custom font size is specified. Hide `fontSizeTextView`.
669 fontSizeTextView.setVisibility(View.GONE);
672 // Open the font size spinner when the `TextView` is clicked.
673 fontSizeTextView.setOnClickListener((View v) -> {
674 // Open the user agent spinner.
675 fontSizeSpinner.performClick();
678 // Display the website images mode in the spinner.
679 displayWebpageImagesSpinner.setSelection(displayImagesInt);
681 // Set the default display images text.
682 if (defaultDisplayWebpageImagesBoolean) {
683 displayImagesTextView.setText(displayImagesArrayAdapter.getItem(DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_ENABLED));
685 displayImagesTextView.setText(displayImagesArrayAdapter.getItem(DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_DISABLED));
688 // 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.
689 switch (displayImagesInt) {
690 case DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_SYSTEM_DEFAULT:
691 if (defaultDisplayWebpageImagesBoolean) { // Display webpage images enabled by default.
692 // Set the icon according to the theme.
693 if (MainWebViewActivity.darkTheme) {
694 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_dark));
696 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_light));
698 } else { // Display webpage images disabled by default.
699 // Set the icon according to the theme.
700 if (MainWebViewActivity.darkTheme) {
701 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_dark));
703 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_light));
707 // Show `displayImagesTextView`.
708 displayImagesTextView.setVisibility(View.VISIBLE);
711 case DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_ENABLED:
712 // Set the icon according to the theme.
713 if (MainWebViewActivity.darkTheme) {
714 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_dark));
716 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_light));
719 // Hide `displayImagesTextView`.
720 displayImagesTextView.setVisibility(View.GONE);
723 case DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_DISABLED:
724 // Set the icon according to the theme.
725 if (MainWebViewActivity.darkTheme) {
726 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_dark));
728 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_light));
731 // Hide `displayImagesTextView`.
732 displayImagesTextView.setVisibility(View.GONE);
736 // Open the display images spinner when the `TextView` is clicked.
737 displayImagesTextView.setOnClickListener((View v) -> {
738 // Open the user agent spinner.
739 displayWebpageImagesSpinner.performClick();
742 // Display the night mode in the spinner.
743 nightModeSpinner.setSelection(nightModeInt);
745 // Set the default night mode text.
746 if (defaultNightModeBoolean) {
747 nightModeTextView.setText(nightModeArrayAdapter.getItem(DomainsDatabaseHelper.NIGHT_MODE_ENABLED));
749 nightModeTextView.setText(nightModeArrayAdapter.getItem(DomainsDatabaseHelper.NIGHT_MODE_DISABLED));
752 // 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.
753 switch (displayImagesInt) {
754 case DomainsDatabaseHelper.NIGHT_MODE_SYSTEM_DEFAULT:
755 if (defaultNightModeBoolean) { // Night mode enabled by default.
756 // Set the icon according to the theme.
757 if (MainWebViewActivity.darkTheme) {
758 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_dark));
760 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_light));
762 } else { // Night mode disabled by default.
763 // Set the icon according to the theme.
764 if (MainWebViewActivity.darkTheme) {
765 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_dark));
767 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_light));
771 // Show `nightModeTextView`.
772 nightModeTextView.setVisibility(View.VISIBLE);
775 case DomainsDatabaseHelper.NIGHT_MODE_ENABLED:
776 // Set the icon according to the theme.
777 if (MainWebViewActivity.darkTheme) {
778 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_dark));
780 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_light));
783 // Hide `nightModeTextView`.
784 nightModeTextView.setVisibility(View.GONE);
787 case DomainsDatabaseHelper.NIGHT_MODE_DISABLED:
788 // Set the icon according to the theme.
789 if (MainWebViewActivity.darkTheme) {
790 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_dark));
792 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_light));
795 // Hide `nightModeTextView`.
796 nightModeTextView.setVisibility(View.GONE);
800 // Open the night mode spinner when the `TextView` is clicked.
801 nightModeTextView.setOnClickListener((View v) -> {
802 // Open the user agent spinner.
803 nightModeSpinner.performClick();
806 // Set the pinned SSL certificate icon.
807 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.
809 pinnedSslCertificateSwitch.setChecked(true);
811 // Set the icon according to the theme.
812 if (MainWebViewActivity.darkTheme) {
813 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_dark));
815 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_light));
817 } else { // Pinned SSL certificate is disabled.
818 // Uncheck the switch.
819 pinnedSslCertificateSwitch.setChecked(false);
821 // Set the icon according to the theme.
822 if (MainWebViewActivity.darkTheme) {
823 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_dark));
825 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_light));
829 // Store the current date.
830 Date currentDate = Calendar.getInstance().getTime();
832 // Setup the `StringBuilders` to display the general certificate information in blue. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
833 savedSslCertificateIssuedToONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), savedSslCertificateIssuedToONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
834 savedSslCertificateIssuedToUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), savedSslCertificateIssuedToUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
835 savedSslCertificateIssuedByCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), savedSslCertificateIssuedByCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
836 savedSslCertificateIssuedByONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), savedSslCertificateIssuedByONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
837 savedSslCertificateIssuedByUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), savedSslCertificateIssuedByUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
839 // Check the certificate `Common Name` against the domain name.
840 boolean savedSSlCertificateCommonNameMatchesDomainName = checkDomainNameAgainstCertificate(domainNameString, savedSslCertificateIssuedToCNameString);
842 // Format the `issuedToCommonName` color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
843 if (savedSSlCertificateCommonNameMatchesDomainName) {
844 savedSslCertificateIssuedToCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), savedSslCertificateIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
846 savedSslCertificateIssuedToCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), savedSslCertificateIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
849 // Format the start date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
850 if ((savedSslCertificateStartDate != null) && savedSslCertificateStartDate.after(currentDate)) { // The certificate start date is in the future.
851 savedSslCertificateStartDateStringBuilder.setSpan(redColorSpan, startDateLabel.length(), savedSslCertificateStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
852 } else { // The certificate start date is in the past.
853 savedSslCertificateStartDateStringBuilder.setSpan(blueColorSpan, startDateLabel.length(), savedSslCertificateStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
856 // Format the end date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
857 if ((savedSslCertificateEndDate != null) && savedSslCertificateEndDate.before(currentDate)) { // The certificate end date is in the past.
858 savedSslCertificateEndDateStringBuilder.setSpan(redColorSpan, endDateLabel.length(), savedSslCertificateEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
859 } else { // The certificate end date is in the future.
860 savedSslCertificateEndDateStringBuilder.setSpan(blueColorSpan, endDateLabel.length(), savedSslCertificateEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
863 // Display the current website SSL certificate strings.
864 savedSslCertificateIssuedToCNameTextView.setText(savedSslCertificateIssuedToCNameStringBuilder);
865 savedSslCertificateIssuedToONameTextView.setText(savedSslCertificateIssuedToONameStringBuilder);
866 savedSslCertificateIssuedToUNameTextView.setText(savedSslCertificateIssuedToUNameStringBuilder);
867 savedSslCertificateIssuedByCNameTextView.setText(savedSslCertificateIssuedByCNameStringBuilder);
868 savedSslCertificateIssuedByONameTextView.setText(savedSslCertificateIssuedByONameStringBuilder);
869 savedSslCertificateIssuedByUNameTextView.setText(savedSslCertificateIssuedByUNameStringBuilder);
870 savedSslCertificateStartDateTextView.setText(savedSslCertificateStartDateStringBuilder);
871 savedSslCertificateEndDateTextView.setText(savedSslCertificateEndDateStringBuilder);
873 // Populate the current website SSL certificate if there is one.
874 if (currentWebsiteSslCertificate != null) {
875 // Get the strings from the SSL certificate.
876 String currentWebsiteCertificateIssuedToCNameString = currentWebsiteSslCertificate.getIssuedTo().getCName();
877 String currentWebsiteCertificateIssuedToONameString = currentWebsiteSslCertificate.getIssuedTo().getOName();
878 String currentWebsiteCertificateIssuedToUNameString = currentWebsiteSslCertificate.getIssuedTo().getUName();
879 String currentWebsiteCertificateIssuedByCNameString = currentWebsiteSslCertificate.getIssuedBy().getCName();
880 String currentWebsiteCertificateIssuedByONameString = currentWebsiteSslCertificate.getIssuedBy().getOName();
881 String currentWebsiteCertificateIssuedByUNameString = currentWebsiteSslCertificate.getIssuedBy().getUName();
882 Date currentWebsiteCertificateStartDate = currentWebsiteSslCertificate.getValidNotBeforeDate();
883 Date currentWebsiteCertificateEndDate = currentWebsiteSslCertificate.getValidNotAfterDate();
885 // Create a `SpannableStringBuilder` for each `TextView` that needs multiple colors of text.
886 SpannableStringBuilder currentWebsiteCertificateIssuedToCNameStringBuilder = new SpannableStringBuilder(cNameLabel + currentWebsiteCertificateIssuedToCNameString);
887 SpannableStringBuilder currentWebsiteCertificateIssuedToONameStringBuilder = new SpannableStringBuilder(oNameLabel + currentWebsiteCertificateIssuedToONameString);
888 SpannableStringBuilder currentWebsiteCertificateIssuedToUNameStringBuilder = new SpannableStringBuilder(uNameLabel + currentWebsiteCertificateIssuedToUNameString);
889 SpannableStringBuilder currentWebsiteCertificateIssuedByCNameStringBuilder = new SpannableStringBuilder(cNameLabel + currentWebsiteCertificateIssuedByCNameString);
890 SpannableStringBuilder currentWebsiteCertificateIssuedByONameStringBuilder = new SpannableStringBuilder(oNameLabel + currentWebsiteCertificateIssuedByONameString);
891 SpannableStringBuilder currentWebsiteCertificateIssuedByUNameStringBuilder = new SpannableStringBuilder(uNameLabel + currentWebsiteCertificateIssuedByUNameString);
892 SpannableStringBuilder currentWebsiteCertificateStartDateStringBuilder = new SpannableStringBuilder(startDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG)
893 .format(currentWebsiteCertificateStartDate));
894 SpannableStringBuilder currentWebsiteCertificateEndDateStringBuilder = new SpannableStringBuilder(endDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG)
895 .format(currentWebsiteCertificateEndDate));
897 // Setup the `StringBuilders` to display the general certificate information in blue. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
898 currentWebsiteCertificateIssuedToONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), currentWebsiteCertificateIssuedToONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
899 currentWebsiteCertificateIssuedToUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), currentWebsiteCertificateIssuedToUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
900 currentWebsiteCertificateIssuedByCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), currentWebsiteCertificateIssuedByCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
901 currentWebsiteCertificateIssuedByONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), currentWebsiteCertificateIssuedByONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
902 currentWebsiteCertificateIssuedByUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), currentWebsiteCertificateIssuedByUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
904 // Check the certificate `Common Name` against the domain name.
905 boolean currentWebsiteCertificateCommonNameMatchesDomainName = checkDomainNameAgainstCertificate(domainNameString, currentWebsiteCertificateIssuedToCNameString);
907 // Format the `issuedToCommonName` color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
908 if (currentWebsiteCertificateCommonNameMatchesDomainName) {
909 currentWebsiteCertificateIssuedToCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), currentWebsiteCertificateIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
911 currentWebsiteCertificateIssuedToCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), currentWebsiteCertificateIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
914 // Format the start date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
915 if (currentWebsiteCertificateStartDate.after(currentDate)) { // The certificate start date is in the future.
916 currentWebsiteCertificateStartDateStringBuilder.setSpan(redColorSpan, startDateLabel.length(), currentWebsiteCertificateStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
917 } else { // The certificate start date is in the past.
918 currentWebsiteCertificateStartDateStringBuilder.setSpan(blueColorSpan, startDateLabel.length(), currentWebsiteCertificateStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
921 // Format the end date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
922 if (currentWebsiteCertificateEndDate.before(currentDate)) { // The certificate end date is in the past.
923 currentWebsiteCertificateEndDateStringBuilder.setSpan(redColorSpan, endDateLabel.length(), currentWebsiteCertificateEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
924 } else { // The certificate end date is in the future.
925 currentWebsiteCertificateEndDateStringBuilder.setSpan(blueColorSpan, endDateLabel.length(), currentWebsiteCertificateEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
928 // Display the current website SSL certificate strings.
929 currentWebsiteCertificateIssuedToCNameTextView.setText(currentWebsiteCertificateIssuedToCNameStringBuilder);
930 currentWebsiteCertificateIssuedToONameTextView.setText(currentWebsiteCertificateIssuedToONameStringBuilder);
931 currentWebsiteCertificateIssuedToUNameTextView.setText(currentWebsiteCertificateIssuedToUNameStringBuilder);
932 currentWebsiteCertificateIssuedByCNameTextView.setText(currentWebsiteCertificateIssuedByCNameStringBuilder);
933 currentWebsiteCertificateIssuedByONameTextView.setText(currentWebsiteCertificateIssuedByONameStringBuilder);
934 currentWebsiteCertificateIssuedByUNameTextView.setText(currentWebsiteCertificateIssuedByUNameStringBuilder);
935 currentWebsiteCertificateStartDateTextView.setText(currentWebsiteCertificateStartDateStringBuilder);
936 currentWebsiteCertificateEndDateTextView.setText(currentWebsiteCertificateEndDateStringBuilder);
939 // Set the initial display status for the SSL certificates.
940 if (pinnedSslCertificateSwitch.isChecked()) {
941 // Set the visibility of the saved SSL certificate.
942 if (savedSslCertificateIssuedToCNameString == null) {
943 savedSslCertificateLinearLayout.setVisibility(View.GONE);
945 savedSslCertificateLinearLayout.setVisibility(View.VISIBLE);
948 // Set the visibility of the current website SSL certificate.
949 if (currentWebsiteSslCertificate == null) {
950 // Hide the SSL certificate.
951 currentWebsiteCertificateLinearLayout.setVisibility(View.GONE);
953 // Show the instruction.
954 noCurrentWebsiteCertificateTextView.setVisibility(View.VISIBLE);
956 // Show the SSL certificate.
957 currentWebsiteCertificateLinearLayout.setVisibility(View.VISIBLE);
959 // Hide the instruction.
960 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
963 // Set the status of the radio buttons.
964 if (savedSslCertificateLinearLayout.getVisibility() == View.VISIBLE) { // The saved SSL certificate is displayed.
965 savedSslCertificateRadioButton.setChecked(true);
966 currentWebsiteCertificateRadioButton.setChecked(false);
967 } else if (currentWebsiteCertificateLinearLayout.getVisibility() == View.VISIBLE) { // The saved SSL certificate is hidden but the current website SSL certificate is visible.
968 currentWebsiteCertificateRadioButton.setChecked(true);
969 savedSslCertificateRadioButton.setChecked(false);
970 } else { // Neither SSL certificate is visible.
971 savedSslCertificateRadioButton.setChecked(false);
972 currentWebsiteCertificateRadioButton.setChecked(false);
974 } else { // `pinnedSslCertificateSwitch` is not checked.
975 // Hide the SSl certificates and instructions.
976 savedSslCertificateLinearLayout.setVisibility(View.GONE);
977 currentWebsiteCertificateLinearLayout.setVisibility(View.GONE);
978 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
980 // Uncheck the radio buttons.
981 savedSslCertificateRadioButton.setChecked(false);
982 currentWebsiteCertificateRadioButton.setChecked(false);
986 // Set the JavaScript switch listener.
987 javaScriptEnabledSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
988 if (isChecked) { // JavaScript is enabled.
989 // Update the JavaScript icon.
990 javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.javascript_enabled));
992 // Enable the DOM storage `Switch`.
993 domStorageEnabledSwitch.setEnabled(true);
995 // Update the DOM storage icon.
996 if (domStorageEnabledSwitch.isChecked()) { // DOM storage is enabled.
997 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_enabled));
998 } else { // DOM storage is disabled.
999 // Set the icon according to the theme.
1000 if (MainWebViewActivity.darkTheme) {
1001 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_dark));
1003 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_light));
1006 } else { // JavaScript is disabled.
1007 // Update the JavaScript icon.
1008 javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.privacy_mode));
1010 // Disable the DOM storage `Switch`.
1011 domStorageEnabledSwitch.setEnabled(false);
1013 // Set the DOM storage icon according to the theme.
1014 if (MainWebViewActivity.darkTheme) {
1015 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_dark));
1017 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_light));
1022 // Set the first-party cookies switch listener.
1023 firstPartyCookiesEnabledSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1024 if (isChecked) { // First-party cookies are enabled.
1025 // Update the first-party cookies icon.
1026 firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_enabled));
1028 // Enable the third-party cookies switch.
1029 thirdPartyCookiesEnabledSwitch.setEnabled(true);
1031 // Update the third-party cookies icon.
1032 if (thirdPartyCookiesEnabledSwitch.isChecked()) { // Third-party cookies are enabled.
1033 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_warning));
1034 } else { // Third-party cookies are disabled.
1035 // Set the third-party cookies icon according to the theme.
1036 if (MainWebViewActivity.darkTheme) {
1037 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_dark));
1039 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_light));
1042 } else { // First-party cookies are disabled.
1043 // Update the first-party cookies icon according to the theme.
1044 if (MainWebViewActivity.darkTheme) {
1045 firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_dark));
1047 firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_light));
1050 // Disable the third-party cookies switch.
1051 thirdPartyCookiesEnabledSwitch.setEnabled(false);
1053 // Set the third-party cookies icon according to the theme.
1054 if (MainWebViewActivity.darkTheme) {
1055 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_ghosted_dark));
1057 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_ghosted_light));
1062 // Set the third-party cookies switch listener.
1063 thirdPartyCookiesEnabledSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1066 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_warning));
1068 // Update the third-party cookies icon according to the theme.
1069 if (MainWebViewActivity.darkTheme) {
1070 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_dark));
1072 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_light));
1077 // Set the DOM Storage switch listener.
1078 domStorageEnabledSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1081 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_enabled));
1083 // Set the icon according to the theme.
1084 if (MainWebViewActivity.darkTheme) {
1085 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_dark));
1087 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_light));
1092 // Set the form data switch listener.
1093 formDataEnabledSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1096 formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_enabled));
1098 // Set the icon according to the theme.
1099 if (MainWebViewActivity.darkTheme) {
1100 formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_disabled_dark));
1102 formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_disabled_light));
1107 // Set the EasyList switch listener.
1108 easyListSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1110 if (isChecked) { // EasyList is on.
1111 // Set the icon according to the theme.
1112 if (MainWebViewActivity.darkTheme) {
1113 easyListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_enabled_dark));
1115 easyListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_enabled_light));
1117 } else { // EasyList is off.
1118 // Set the icon according to the theme.
1119 if (MainWebViewActivity.darkTheme) {
1120 easyListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_disabled_dark));
1122 easyListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_disabled_light));
1127 // Set the EasyPrivacy switch listener.
1128 easyPrivacySwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1130 if (isChecked) { // EasyPrivacy is on.
1131 // Set the icon according to the theme.
1132 if (MainWebViewActivity.darkTheme) {
1133 easyPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_enabled_dark));
1135 easyPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_enabled_light));
1137 } else { // EasyPrivacy is off.
1138 // Set the icon according to the theme.
1139 if (MainWebViewActivity.darkTheme) {
1140 easyPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_disabled_dark));
1142 easyPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_disabled_light));
1147 // Set the Fanboy's Annoyance List switch listener.
1148 fanboysAnnoyanceListSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1149 // Update the icon and Fanboy's Social Blocking List.
1150 if (isChecked) { // Fanboy's Annoyance List is on.
1151 // Set the icon according to the theme.
1152 if (MainWebViewActivity.darkTheme) {
1153 fanboysAnnoyanceListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_dark));
1155 fanboysAnnoyanceListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_light));
1158 // Disable the Fanboy's Social Blocking List switch.
1159 fanboysSocialBlockingListSwitch.setEnabled(false);
1161 // Update the Fanboy's Social Blocking List icon according to the theme.
1162 if (MainWebViewActivity.darkTheme) {
1163 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_ghosted_dark));
1165 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_ghosted_light));
1167 } else { // Fanboy's Annoyance List is off.
1168 // Set the icon according to the theme.
1169 if (MainWebViewActivity.darkTheme) {
1170 fanboysAnnoyanceListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_dark));
1172 fanboysAnnoyanceListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_light));
1175 // Enable the Fanboy's Social Blocking List switch.
1176 fanboysSocialBlockingListSwitch.setEnabled(true);
1178 // Update the Fanboy's Social Blocking List icon.
1179 if (fanboysSocialBlockingListSwitch.isChecked()) { // Fanboy's Social Blocking List is on.
1180 // Update the icon according to the theme.
1181 if (MainWebViewActivity.darkTheme) {
1182 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_dark));
1184 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_light));
1186 } else { // Fanboy's Social Blocking List is off.
1187 // Update the icon according to the theme.
1188 if (MainWebViewActivity.darkTheme) {
1189 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_dark));
1191 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_light));
1198 // Set the Fanboy's Social Blocking List switch listener.
1199 fanboysSocialBlockingListSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1201 if (isChecked) { // Fanboy's Social Blocking List is on.
1202 // Set the icon according to the theme.
1203 if (MainWebViewActivity.darkTheme) {
1204 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_dark));
1206 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_light));
1208 } else { // Fanboy's Social Blocking List is off.
1209 // Set the icon according to the theme.
1210 if (MainWebViewActivity.darkTheme) {
1211 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_dark));
1213 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_light));
1218 // Set the user agent spinner listener.
1219 userAgentSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1221 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1222 // Set the new user agent.
1224 case MainWebViewActivity.DOMAINS_SYSTEM_DEFAULT_USER_AGENT:
1225 // Show the user agent TextView.
1226 userAgentTextView.setVisibility(View.VISIBLE);
1228 // Hide the custom user agent EditText.
1229 customUserAgentEditText.setVisibility(View.GONE);
1231 // Set the user text.
1232 switch (defaultUserAgentArrayPosition) {
1233 case MainWebViewActivity.UNRECOGNIZED_USER_AGENT: // The default user agent name is not on the canonical list.
1234 // This is probably because it was set in an older version of Privacy Browser before the switch to persistent user agent names.
1235 userAgentTextView.setText(defaultUserAgentName);
1238 case MainWebViewActivity.SETTINGS_WEBVIEW_DEFAULT_USER_AGENT:
1239 // Display the `WebView` default user agent.
1240 userAgentTextView.setText(webViewDefaultUserAgentString);
1243 case MainWebViewActivity.SETTINGS_CUSTOM_USER_AGENT:
1244 // Display the custom user agent.
1245 userAgentTextView.setText(defaultCustomUserAgentString);
1249 // Get the user agent string from the user agent data array.
1250 userAgentTextView.setText(userAgentDataArray[defaultUserAgentArrayPosition]);
1254 case MainWebViewActivity.DOMAINS_WEBVIEW_DEFAULT_USER_AGENT:
1255 // Show the user agent TextView and set the text.
1256 userAgentTextView.setVisibility(View.VISIBLE);
1257 userAgentTextView.setText(webViewDefaultUserAgentString);
1259 // Hide the custom user agent EditTex.
1260 customUserAgentEditText.setVisibility(View.GONE);
1263 case MainWebViewActivity.DOMAINS_CUSTOM_USER_AGENT:
1264 // Hide the user agent TextView.
1265 userAgentTextView.setVisibility(View.GONE);
1267 // Show the custom user agent EditText and set the current user agent name as the text.
1268 customUserAgentEditText.setVisibility(View.VISIBLE);
1269 customUserAgentEditText.setText(currentUserAgentName);
1273 // 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.
1274 userAgentTextView.setVisibility(View.VISIBLE);
1275 userAgentTextView.setText(userAgentDataArray[position - 1]);
1277 // Hide `customUserAgentEditText`.
1278 customUserAgentEditText.setVisibility(View.GONE);
1283 public void onNothingSelected(AdapterView<?> parent) {
1288 // Set the font size spinner listener.
1289 fontSizeSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1291 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1292 // Update the display options for `fontSizeTextView`.
1293 if (position == 0) { // System default font size has been selected. Display `fontSizeTextView`.
1294 fontSizeTextView.setVisibility(View.VISIBLE);
1295 } else { // A custom font size has been selected. Hide `fontSizeTextView`.
1296 fontSizeTextView.setVisibility(View.GONE);
1301 public void onNothingSelected(AdapterView<?> parent) {
1306 // Set the display webpage images spinner listener.
1307 displayWebpageImagesSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1309 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1310 // Update the icon and the visibility of `displayImagesTextView`.
1312 case DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_SYSTEM_DEFAULT:
1313 if (defaultDisplayWebpageImagesBoolean) {
1314 // Set the icon according to the theme.
1315 if (MainWebViewActivity.darkTheme) {
1316 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_dark));
1318 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_light));
1321 // Set the icon according to the theme.
1322 if (MainWebViewActivity.darkTheme) {
1323 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_dark));
1325 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_light));
1329 // Show `displayImagesTextView`.
1330 displayImagesTextView.setVisibility(View.VISIBLE);
1333 case DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_ENABLED:
1334 // Set the icon according to the theme.
1335 if (MainWebViewActivity.darkTheme) {
1336 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_dark));
1338 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_light));
1341 // Hide `displayImagesTextView`.
1342 displayImagesTextView.setVisibility(View.GONE);
1345 case DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_DISABLED:
1346 // Set the icon according to the theme.
1347 if (MainWebViewActivity.darkTheme) {
1348 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_dark));
1350 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_light));
1353 // Hide `displayImagesTextView`.
1354 displayImagesTextView.setVisibility(View.GONE);
1360 public void onNothingSelected(AdapterView<?> parent) {
1365 // Set the night mode spinner listener.
1366 nightModeSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1368 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1369 // 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.
1371 case DomainsDatabaseHelper.NIGHT_MODE_SYSTEM_DEFAULT:
1372 if (defaultNightModeBoolean) { // Night mode enabled by default.
1373 // Set the icon according to the theme.
1374 if (MainWebViewActivity.darkTheme) {
1375 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_dark));
1377 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_light));
1379 } else { // Night mode disabled by default.
1380 // Set the icon according to the theme.
1381 if (MainWebViewActivity.darkTheme) {
1382 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_dark));
1384 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_light));
1388 // Show `nightModeTextView`.
1389 nightModeTextView.setVisibility(View.VISIBLE);
1392 case DomainsDatabaseHelper.NIGHT_MODE_ENABLED:
1393 // Set the icon according to the theme.
1394 if (MainWebViewActivity.darkTheme) {
1395 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_dark));
1397 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_light));
1400 // Hide `nightModeTextView`.
1401 nightModeTextView.setVisibility(View.GONE);
1404 case DomainsDatabaseHelper.NIGHT_MODE_DISABLED:
1405 // Set the icon according to the theme.
1406 if (MainWebViewActivity.darkTheme) {
1407 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_dark));
1409 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_light));
1412 // Hide `nightModeTextView`.
1413 nightModeTextView.setVisibility(View.GONE);
1417 // Create a `boolean` to store the current night mode setting.
1418 boolean currentNightModeEnabled = (position == DomainsDatabaseHelper.NIGHT_MODE_ENABLED) || ((position == DomainsDatabaseHelper.NIGHT_MODE_SYSTEM_DEFAULT) && defaultNightModeBoolean);
1420 // Disable the JavaScript `Switch` if night mode is enabled.
1421 if (currentNightModeEnabled) {
1422 javaScriptEnabledSwitch.setEnabled(false);
1424 javaScriptEnabledSwitch.setEnabled(true);
1427 // Update the JavaScript icon.
1428 if ((javaScriptEnabledInt == 1) || currentNightModeEnabled) {
1429 javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.javascript_enabled));
1431 javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.privacy_mode));
1434 // Update the DOM storage status.
1435 if ((javaScriptEnabledInt == 1) || currentNightModeEnabled) { // JavaScript is enabled.
1436 // Enable the DOM storage `Switch`.
1437 domStorageEnabledSwitch.setEnabled(true);
1439 // Set the DOM storage status. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
1440 if (domStorageEnabledInt == 1) { // Both JavaScript and DOM storage are enabled.
1441 domStorageEnabledSwitch.setChecked(true);
1442 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_enabled));
1443 } else { // JavaScript is enabled but DOM storage is disabled.
1444 // Set the DOM storage switch to off.
1445 domStorageEnabledSwitch.setChecked(false);
1447 // Set the icon according to the theme.
1448 if (MainWebViewActivity.darkTheme) {
1449 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_dark));
1451 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_light));
1454 } else { // JavaScript is disabled.
1455 // Disable the DOM storage `Switch`.
1456 domStorageEnabledSwitch.setEnabled(false);
1458 // Set the checked status of DOM storage.
1459 if (domStorageEnabledInt == 1) { // DOM storage is enabled but JavaScript is disabled.
1460 domStorageEnabledSwitch.setChecked(true);
1461 } else { // Both JavaScript and DOM storage are disabled.
1462 domStorageEnabledSwitch.setChecked(false);
1465 // Set the icon according to the theme.
1466 if (MainWebViewActivity.darkTheme) {
1467 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_dark));
1469 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_light));
1475 public void onNothingSelected(AdapterView<?> parent) {
1480 // Set the pinned SSL certificate switch listener.
1481 pinnedSslCertificateSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1483 if (isChecked) { // Pinned SSL certificate is enabled.
1484 // Set the icon according to the theme.
1485 if (MainWebViewActivity.darkTheme) {
1486 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_dark));
1488 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_light));
1491 // Update the visibility of the saved SSL certificate.
1492 if (savedSslCertificateIssuedToCNameString == null) {
1493 savedSslCertificateLinearLayout.setVisibility(View.GONE);
1495 savedSslCertificateLinearLayout.setVisibility(View.VISIBLE);
1498 // Update the visibility of the current website SSL certificate.
1499 if (currentWebsiteSslCertificate == null) {
1500 // Hide the SSL certificate.
1501 currentWebsiteCertificateLinearLayout.setVisibility(View.GONE);
1503 // Show the instruction.
1504 noCurrentWebsiteCertificateTextView.setVisibility(View.VISIBLE);
1506 // Show the SSL certificate.
1507 currentWebsiteCertificateLinearLayout.setVisibility(View.VISIBLE);
1509 // Hide the instruction.
1510 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
1513 // Set the status of the radio buttons.
1514 if (savedSslCertificateLinearLayout.getVisibility() == View.VISIBLE) { // The saved SSL certificate is displayed.
1515 savedSslCertificateRadioButton.setChecked(true);
1516 currentWebsiteCertificateRadioButton.setChecked(false);
1517 } else if (currentWebsiteCertificateLinearLayout.getVisibility() == View.VISIBLE) { // The saved SSL certificate is hidden but the current website SSL certificate is visible.
1518 currentWebsiteCertificateRadioButton.setChecked(true);
1519 savedSslCertificateRadioButton.setChecked(false);
1520 } else { // Neither SSL certificate is visible.
1521 savedSslCertificateRadioButton.setChecked(false);
1522 currentWebsiteCertificateRadioButton.setChecked(false);
1524 } else { // Pinned SSL certificate is disabled.
1525 // Set the icon according to the theme.
1526 if (MainWebViewActivity.darkTheme) {
1527 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_dark));
1529 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_light));
1532 // Hide the SSl certificates and instructions.
1533 savedSslCertificateLinearLayout.setVisibility(View.GONE);
1534 currentWebsiteCertificateLinearLayout.setVisibility(View.GONE);
1535 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
1537 // Uncheck the radio buttons.
1538 savedSslCertificateRadioButton.setChecked(false);
1539 currentWebsiteCertificateRadioButton.setChecked(false);
1543 savedSslCertificateLinearLayout.setOnClickListener((View v) -> {
1544 savedSslCertificateRadioButton.setChecked(true);
1545 currentWebsiteCertificateRadioButton.setChecked(false);
1548 savedSslCertificateRadioButton.setOnClickListener((View v) -> {
1549 savedSslCertificateRadioButton.setChecked(true);
1550 currentWebsiteCertificateRadioButton.setChecked(false);
1553 currentWebsiteCertificateLinearLayout.setOnClickListener((View v) -> {
1554 currentWebsiteCertificateRadioButton.setChecked(true);
1555 savedSslCertificateRadioButton.setChecked(false);
1558 currentWebsiteCertificateRadioButton.setOnClickListener((View v) -> {
1559 currentWebsiteCertificateRadioButton.setChecked(true);
1560 savedSslCertificateRadioButton.setChecked(false);
1563 return domainSettingsView;
1566 private boolean checkDomainNameAgainstCertificate(String domainName, String certificateCommonName) {
1567 // Initialize `domainNamesMatch`.
1568 boolean domainNamesMatch = false;
1570 // Check if the domains match.
1571 if (domainName.equals(certificateCommonName)) {
1572 domainNamesMatch = true;
1575 // Check various wildcard permutations if `domainName` and `certificateCommonName` are not empty.
1576 // `noinspection ConstantCondition` removes Android Studio's incorrect lint warning that `domainName` can never be `null`.
1577 //noinspection ConstantConditions
1578 if ((domainName != null) && (certificateCommonName != null)) {
1579 // If `domainName` starts with a wildcard, check the base domain against all the subdomains of `certificateCommonName`.
1580 if (!domainNamesMatch && domainName.startsWith("*.") && (domainName.length() > 2)) {
1581 // Remove the initial `*.`.
1582 String baseDomainName = domainName.substring(2);
1584 // Setup a copy of `certificateCommonName` to test subdomains.
1585 String certificateCommonNameSubdomain = certificateCommonName;
1587 // Check all the subdomains in `certificateCommonNameSubdomain` against `baseDomainName`.
1588 while (!domainNamesMatch && certificateCommonNameSubdomain.contains(".")) { // Stop checking if we know that `domainNamesMatch` is `true` or if we run out of `.`.
1589 // Test the `certificateCommonNameSubdomain` against `baseDomainName`.
1590 if (certificateCommonNameSubdomain.equals(baseDomainName)) {
1591 domainNamesMatch = true;
1594 // Strip out the lowest subdomain of `certificateCommonNameSubdomain`.
1596 certificateCommonNameSubdomain = certificateCommonNameSubdomain.substring(certificateCommonNameSubdomain.indexOf(".") + 1);
1597 } catch (IndexOutOfBoundsException e) { // `certificateCommonNameSubdomain` ends with `.`.
1598 certificateCommonNameSubdomain = "";
1603 // If `certificateCommonName` starts with a wildcard, check the base common name against all the subdomains of `domainName`.
1604 if (!domainNamesMatch && certificateCommonName.startsWith("*.") && (certificateCommonName.length() > 2)) {
1605 // Remove the initial `*.`.
1606 String baseCertificateCommonName = certificateCommonName.substring(2);
1608 // Setup a copy of `domainName` to test subdomains.
1609 String domainNameSubdomain = domainName;
1611 // Check all the subdomains in `domainNameSubdomain` against `baseCertificateCommonName`.
1612 while (!domainNamesMatch && domainNameSubdomain.contains(".") && (domainNameSubdomain.length() > 2)) {
1613 // Test the `domainNameSubdomain` against `baseCertificateCommonName`.
1614 if (domainNameSubdomain.equals(baseCertificateCommonName)) {
1615 domainNamesMatch = true;
1618 // Strip out the lowest subdomain of `domainNameSubdomain`.
1620 domainNameSubdomain = domainNameSubdomain.substring(domainNameSubdomain.indexOf(".") + 1);
1621 } catch (IndexOutOfBoundsException e) { // `domainNameSubdomain` ends with `.`.
1622 domainNameSubdomain = "";
1627 // If both names start with a wildcard, check if the root of one contains the root of the other.
1628 if (!domainNamesMatch && domainName.startsWith("*.") && (domainName.length() > 2) && certificateCommonName.startsWith("*.") && (certificateCommonName.length() > 2)) {
1629 // Remove the wildcards.
1630 String rootDomainName = domainName.substring(2);
1631 String rootCertificateCommonName = certificateCommonName.substring(2);
1633 // Check if one name ends with the contents of the other. If so, there will be overlap in the their wildcard subdomains.
1634 if (rootDomainName.endsWith(rootCertificateCommonName) || rootCertificateCommonName.endsWith(rootDomainName)) {
1635 domainNamesMatch = true;
1640 return domainNamesMatch;