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.os.Build;
28 import android.os.Bundle;
29 import android.preference.PreferenceManager;
30 import android.text.Editable;
31 import android.text.SpannableStringBuilder;
32 import android.text.Spanned;
33 import android.text.TextWatcher;
34 import android.text.style.ForegroundColorSpan;
35 import android.view.LayoutInflater;
36 import android.view.View;
37 import android.view.ViewGroup;
38 import android.webkit.WebView;
39 import android.widget.AdapterView;
40 import android.widget.ArrayAdapter;
41 import android.widget.CompoundButton;
42 import android.widget.EditText;
43 import android.widget.ImageView;
44 import android.widget.LinearLayout;
45 import android.widget.RadioButton;
46 import android.widget.Spinner;
47 import android.widget.Switch;
48 import android.widget.TextView;
50 import androidx.annotation.NonNull;
51 import androidx.cardview.widget.CardView;
52 import androidx.fragment.app.Fragment; // The AndroidX fragment must be used until minimum API >= 23. Otherwise `getContext()` does not work.
54 import com.stoutner.privacybrowser.R;
55 import com.stoutner.privacybrowser.activities.DomainsActivity;
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 // Run the default commands.
73 super.onCreate(savedInstanceState);
75 // Remove the lint warning that `getArguments` might be null.
76 assert getArguments() != null;
78 // Store the database id in `databaseId`.
79 databaseId = getArguments().getInt(DATABASE_ID);
82 // The deprecated `getDrawable()` must be used until the minimum API >= 21.
84 public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
85 // Inflate `domain_settings_fragment`. `false` does not attach it to the root `container`.
86 View domainSettingsView = inflater.inflate(R.layout.domain_settings_fragment, container, false);
88 // Get a handle for the context and the resources.
89 Context context = getContext();
90 Resources resources = getResources();
92 // Remove the error below that the context might be null.
93 assert context != null;
95 // Get a handle for the shared preference.
96 SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
98 // Store the default settings.
99 String defaultUserAgentName = sharedPreferences.getString("user_agent", getString(R.string.user_agent_default_value));
100 String defaultCustomUserAgentString = sharedPreferences.getString("custom_user_agent", getString(R.string.custom_user_agent_default_value));
101 String defaultFontSizeString = sharedPreferences.getString("font_size", getString(R.string.font_size_default_value));
102 boolean defaultSwipeToRefresh = sharedPreferences.getBoolean("swipe_to_refresh", true);
103 boolean darkTheme = sharedPreferences.getBoolean("dark_theme", false);
104 boolean defaultNightMode = sharedPreferences.getBoolean("night_mode", false);
105 boolean defaultWideViewport = sharedPreferences.getBoolean("wide_viewport", true);
106 boolean defaultDisplayWebpageImages = sharedPreferences.getBoolean("display_webpage_images", true);
108 // Get handles for the views in the fragment.
109 EditText domainNameEditText = domainSettingsView.findViewById(R.id.domain_settings_name_edittext);
110 Switch javaScriptEnabledSwitch = domainSettingsView.findViewById(R.id.javascript_switch);
111 ImageView javaScriptImageView = domainSettingsView.findViewById(R.id.javascript_imageview);
112 Switch firstPartyCookiesEnabledSwitch = domainSettingsView.findViewById(R.id.first_party_cookies_switch);
113 ImageView firstPartyCookiesImageView = domainSettingsView.findViewById(R.id.first_party_cookies_imageview);
114 LinearLayout thirdPartyCookiesLinearLayout = domainSettingsView.findViewById(R.id.third_party_cookies_linearlayout);
115 Switch thirdPartyCookiesEnabledSwitch = domainSettingsView.findViewById(R.id.third_party_cookies_switch);
116 ImageView thirdPartyCookiesImageView = domainSettingsView.findViewById(R.id.third_party_cookies_imageview);
117 Switch domStorageEnabledSwitch = domainSettingsView.findViewById(R.id.dom_storage_switch);
118 ImageView domStorageImageView = domainSettingsView.findViewById(R.id.dom_storage_imageview);
119 Switch formDataEnabledSwitch = domainSettingsView.findViewById(R.id.form_data_switch); // The form data views can be remove once the minimum API >= 26.
120 ImageView formDataImageView = domainSettingsView.findViewById(R.id.form_data_imageview); // The form data views can be remove once the minimum API >= 26.
121 Switch easyListSwitch = domainSettingsView.findViewById(R.id.easylist_switch);
122 ImageView easyListImageView = domainSettingsView.findViewById(R.id.easylist_imageview);
123 Switch easyPrivacySwitch = domainSettingsView.findViewById(R.id.easyprivacy_switch);
124 ImageView easyPrivacyImageView = domainSettingsView.findViewById(R.id.easyprivacy_imageview);
125 Switch fanboysAnnoyanceListSwitch = domainSettingsView.findViewById(R.id.fanboys_annoyance_list_switch);
126 ImageView fanboysAnnoyanceListImageView = domainSettingsView.findViewById(R.id.fanboys_annoyance_list_imageview);
127 Switch fanboysSocialBlockingListSwitch = domainSettingsView.findViewById(R.id.fanboys_social_blocking_list_switch);
128 ImageView fanboysSocialBlockingListImageView = domainSettingsView.findViewById(R.id.fanboys_social_blocking_list_imageview);
129 Switch ultraPrivacySwitch = domainSettingsView.findViewById(R.id.ultraprivacy_switch);
130 ImageView ultraPrivacyImageView = domainSettingsView.findViewById(R.id.ultraprivacy_imageview);
131 Switch blockAllThirdPartyRequestsSwitch = domainSettingsView.findViewById(R.id.block_all_third_party_requests_switch);
132 ImageView blockAllThirdPartyRequestsImageView = domainSettingsView.findViewById(R.id.block_all_third_party_requests_imageview);
133 Spinner userAgentSpinner = domainSettingsView.findViewById(R.id.user_agent_spinner);
134 TextView userAgentTextView = domainSettingsView.findViewById(R.id.user_agent_textview);
135 EditText customUserAgentEditText = domainSettingsView.findViewById(R.id.custom_user_agent_edittext);
136 Spinner fontSizeSpinner = domainSettingsView.findViewById(R.id.font_size_spinner);
137 TextView fontSizeTextView = domainSettingsView.findViewById(R.id.font_size_textview);
138 ImageView swipeToRefreshImageView = domainSettingsView.findViewById(R.id.swipe_to_refresh_imageview);
139 Spinner swipeToRefreshSpinner = domainSettingsView.findViewById(R.id.swipe_to_refresh_spinner);
140 TextView swipeToRefreshTextView = domainSettingsView.findViewById(R.id.swipe_to_refresh_textview);
141 ImageView nightModeImageView = domainSettingsView.findViewById(R.id.night_mode_imageview);
142 Spinner nightModeSpinner = domainSettingsView.findViewById(R.id.night_mode_spinner);
143 TextView nightModeTextView = domainSettingsView.findViewById(R.id.night_mode_textview);
144 ImageView wideViewportImageView = domainSettingsView.findViewById(R.id.wide_viewport_imageview);
145 Spinner wideViewportSpinner = domainSettingsView.findViewById(R.id.wide_viewport_spinner);
146 TextView wideViewportTextView = domainSettingsView.findViewById(R.id.wide_viewport_textview);
147 ImageView displayWebpageImagesImageView = domainSettingsView.findViewById(R.id.display_webpage_images_imageview);
148 Spinner displayWebpageImagesSpinner = domainSettingsView.findViewById(R.id.display_webpage_images_spinner);
149 TextView displayImagesTextView = domainSettingsView.findViewById(R.id.display_webpage_images_textview);
150 ImageView pinnedSslCertificateImageView = domainSettingsView.findViewById(R.id.pinned_ssl_certificate_imageview);
151 Switch pinnedSslCertificateSwitch = domainSettingsView.findViewById(R.id.pinned_ssl_certificate_switch);
152 CardView savedSslCardView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_cardview);
153 LinearLayout savedSslCertificateLinearLayout = domainSettingsView.findViewById(R.id.saved_ssl_certificate_linearlayout);
154 RadioButton savedSslCertificateRadioButton = domainSettingsView.findViewById(R.id.saved_ssl_certificate_radiobutton);
155 TextView savedSslIssuedToCNameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_to_cname);
156 TextView savedSslIssuedToONameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_to_oname);
157 TextView savedSslIssuedToUNameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_to_uname);
158 TextView savedSslIssuedByCNameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_by_cname);
159 TextView savedSslIssuedByONameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_by_oname);
160 TextView savedSslIssuedByUNameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_by_uname);
161 TextView savedSslStartDateTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_start_date);
162 TextView savedSslEndDateTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_end_date);
163 CardView currentSslCardView = domainSettingsView.findViewById(R.id.current_website_certificate_cardview);
164 LinearLayout currentWebsiteCertificateLinearLayout = domainSettingsView.findViewById(R.id.current_website_certificate_linearlayout);
165 RadioButton currentWebsiteCertificateRadioButton = domainSettingsView.findViewById(R.id.current_website_certificate_radiobutton);
166 TextView currentSslIssuedToCNameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_to_cname);
167 TextView currentSslIssuedToONameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_to_oname);
168 TextView currentSslIssuedToUNameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_to_uname);
169 TextView currentSslIssuedByCNameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_by_cname);
170 TextView currentSslIssuedByONameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_by_oname);
171 TextView currentSslIssuedByUNameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_by_uname);
172 TextView currentSslStartDateTextView = domainSettingsView.findViewById(R.id.current_website_certificate_start_date);
173 TextView currentSslEndDateTextView = domainSettingsView.findViewById(R.id.current_website_certificate_end_date);
174 TextView noCurrentWebsiteCertificateTextView = domainSettingsView.findViewById(R.id.no_current_website_certificate);
175 ImageView pinnedIpAddressesImageView = domainSettingsView.findViewById(R.id.pinned_ip_addresses_imageview);
176 Switch pinnedIpAddressesSwitch = domainSettingsView.findViewById(R.id.pinned_ip_addresses_switch);
177 CardView savedIpAddressesCardView = domainSettingsView.findViewById(R.id.saved_ip_addresses_cardview);
178 LinearLayout savedIpAddressesLinearLayout = domainSettingsView.findViewById(R.id.saved_ip_addresses_linearlayout);
179 RadioButton savedIpAddressesRadioButton = domainSettingsView.findViewById(R.id.saved_ip_addresses_radiobutton);
180 TextView savedIpAddressesTextView = domainSettingsView.findViewById(R.id.saved_ip_addresses_textview);
181 CardView currentIpAddressesCardView = domainSettingsView.findViewById(R.id.current_ip_addresses_cardview);
182 LinearLayout currentIpAddressesLinearLayout = domainSettingsView.findViewById(R.id.current_ip_addresses_linearlayout);
183 RadioButton currentIpAddressesRadioButton = domainSettingsView.findViewById(R.id.current_ip_addresses_radiobutton);
184 TextView currentIpAddressesTextView = domainSettingsView.findViewById(R.id.current_ip_addresses_textview);
186 // Setup the pinned labels.
187 String cNameLabel = getString(R.string.common_name) + " ";
188 String oNameLabel = getString(R.string.organization) + " ";
189 String uNameLabel = getString(R.string.organizational_unit) + " ";
190 String startDateLabel = getString(R.string.start_date) + " ";
191 String endDateLabel = getString(R.string.end_date) + " ";
193 // Initialize the database handler. The `0` specifies the database version, but that is ignored and set instead using a constant in `DomainsDatabaseHelper`.
194 DomainsDatabaseHelper domainsDatabaseHelper = new DomainsDatabaseHelper(context, null, null, 0);
196 // Get the database cursor for this ID and move it to the first row.
197 Cursor domainCursor = domainsDatabaseHelper.getCursorForId(databaseId);
198 domainCursor.moveToFirst();
200 // Save the cursor entries as variables.
201 String domainNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.DOMAIN_NAME));
202 int javaScriptEnabledInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_JAVASCRIPT));
203 int firstPartyCookiesEnabledInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FIRST_PARTY_COOKIES));
204 int thirdPartyCookiesEnabledInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_THIRD_PARTY_COOKIES));
205 int domStorageEnabledInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_DOM_STORAGE));
206 int formDataEnabledInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FORM_DATA)); // Form data can be remove once the minimum API >= 26.
207 int easyListEnabledInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_EASYLIST));
208 int easyPrivacyEnabledInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_EASYPRIVACY));
209 int fanboysAnnoyanceListInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FANBOYS_ANNOYANCE_LIST));
210 int fanboysSocialBlockingListInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FANBOYS_SOCIAL_BLOCKING_LIST));
211 int ultraPrivacyEnabledInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_ULTRAPRIVACY));
212 int blockAllThirdPartyRequestsInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.BLOCK_ALL_THIRD_PARTY_REQUESTS));
213 String currentUserAgentName = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.USER_AGENT));
214 int fontSizeInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.FONT_SIZE));
215 int swipeToRefreshInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.SWIPE_TO_REFRESH));
216 int nightModeInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.NIGHT_MODE));
217 int wideViewportInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.WIDE_VIEWPORT));
218 int displayImagesInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.DISPLAY_IMAGES));
219 int pinnedSslCertificateInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.PINNED_SSL_CERTIFICATE));
220 String savedSslIssuedToCNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_TO_COMMON_NAME));
221 String savedSslIssuedToONameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_TO_ORGANIZATION));
222 String savedSslIssuedToUNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_TO_ORGANIZATIONAL_UNIT));
223 String savedSslIssuedByCNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_BY_COMMON_NAME));
224 String savedSslIssuedByONameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_BY_ORGANIZATION));
225 String savedSslIssuedByUNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_BY_ORGANIZATIONAL_UNIT));
226 int pinnedIpAddressesInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.PINNED_IP_ADDRESSES));
227 String savedIpAddresses = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.IP_ADDRESSES));
229 // Initialize the saved SSL certificate date variables.
230 Date savedSslStartDate = null;
231 Date savedSslEndDate = null;
233 // Only get the saved SSL certificate dates from the cursor if they are not set to `0`.
234 if (domainCursor.getLong(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_START_DATE)) != 0) {
235 savedSslStartDate = new Date(domainCursor.getLong(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_START_DATE)));
238 if (domainCursor.getLong(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_END_DATE)) != 0) {
239 savedSslEndDate = new Date(domainCursor.getLong(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_END_DATE)));
242 // Create array adapters for the spinners.
243 ArrayAdapter<CharSequence> translatedUserAgentArrayAdapter = ArrayAdapter.createFromResource(context, R.array.translated_domain_settings_user_agent_names, R.layout.spinner_item);
244 ArrayAdapter<CharSequence> fontSizeArrayAdapter = ArrayAdapter.createFromResource(context, R.array.domain_settings_font_size_entries, R.layout.spinner_item);
245 ArrayAdapter<CharSequence> fontSizeEntryValuesArrayAdapter = ArrayAdapter.createFromResource(context, R.array.domain_settings_font_size_entry_values, R.layout.spinner_item);
246 ArrayAdapter<CharSequence> swipeToRefreshArrayAdapter = ArrayAdapter.createFromResource(context, R.array.swipe_to_refresh_array, R.layout.spinner_item);
247 ArrayAdapter<CharSequence> nightModeArrayAdapter = ArrayAdapter.createFromResource(context, R.array.night_mode_array, R.layout.spinner_item);
248 ArrayAdapter<CharSequence> wideViewportArrayAdapter = ArrayAdapter.createFromResource(context, R.array.wide_viewport_array, R.layout.spinner_item);
249 ArrayAdapter<CharSequence> displayImagesArrayAdapter = ArrayAdapter.createFromResource(context, R.array.display_webpage_images_array, R.layout.spinner_item);
251 // Set the drop down view resource on the spinners.
252 translatedUserAgentArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items);
253 fontSizeArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items);
254 swipeToRefreshArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items);
255 nightModeArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items);
256 wideViewportArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items);
257 displayImagesArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items);
259 // Set the array adapters for the spinners.
260 userAgentSpinner.setAdapter(translatedUserAgentArrayAdapter);
261 fontSizeSpinner.setAdapter(fontSizeArrayAdapter);
262 swipeToRefreshSpinner.setAdapter(swipeToRefreshArrayAdapter);
263 nightModeSpinner.setAdapter(nightModeArrayAdapter);
264 wideViewportSpinner.setAdapter(wideViewportArrayAdapter);
265 displayWebpageImagesSpinner.setAdapter(displayImagesArrayAdapter);
267 // Create a spannable string builder for each TextView that needs multiple colors of text.
268 SpannableStringBuilder savedSslIssuedToCNameStringBuilder = new SpannableStringBuilder(cNameLabel + savedSslIssuedToCNameString);
269 SpannableStringBuilder savedSslIssuedToONameStringBuilder = new SpannableStringBuilder(oNameLabel + savedSslIssuedToONameString);
270 SpannableStringBuilder savedSslIssuedToUNameStringBuilder = new SpannableStringBuilder(uNameLabel + savedSslIssuedToUNameString);
271 SpannableStringBuilder savedSslIssuedByCNameStringBuilder = new SpannableStringBuilder(cNameLabel + savedSslIssuedByCNameString);
272 SpannableStringBuilder savedSslIssuedByONameStringBuilder = new SpannableStringBuilder(oNameLabel + savedSslIssuedByONameString);
273 SpannableStringBuilder savedSslIssuedByUNameStringBuilder = new SpannableStringBuilder(uNameLabel + savedSslIssuedByUNameString);
275 // Initialize the spannable string builders for the saved SSL certificate dates.
276 SpannableStringBuilder savedSslStartDateStringBuilder;
277 SpannableStringBuilder savedSslEndDateStringBuilder;
279 // Leave the SSL certificate dates empty if they are `null`.
280 if (savedSslStartDate == null) {
281 savedSslStartDateStringBuilder = new SpannableStringBuilder(startDateLabel);
283 savedSslStartDateStringBuilder = new SpannableStringBuilder(startDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(savedSslStartDate));
286 if (savedSslEndDate == null) {
287 savedSslEndDateStringBuilder = new SpannableStringBuilder(endDateLabel);
289 savedSslEndDateStringBuilder = new SpannableStringBuilder(endDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(savedSslEndDate));
292 // Create a red foreground color span. The deprecated `resources.getColor` must be used until the minimum API >= 23.
293 final ForegroundColorSpan redColorSpan = new ForegroundColorSpan(resources.getColor(R.color.red_a700));
295 // Create a blue foreground color span.
296 final ForegroundColorSpan blueColorSpan;
298 // Set the blue color span according to the theme. The deprecated `resources.getColor` must be used until the minimum API >= 23.
300 blueColorSpan = new ForegroundColorSpan(resources.getColor(R.color.blue_400));
302 blueColorSpan = new ForegroundColorSpan(resources.getColor(R.color.blue_700));
305 // Set the domain name from the the database cursor.
306 domainNameEditText.setText(domainNameString);
308 // Update the certificates' `Common Name` color when the domain name text changes.
309 domainNameEditText.addTextChangedListener(new TextWatcher() {
311 public void beforeTextChanged(CharSequence s, int start, int count, int after) {
316 public void onTextChanged(CharSequence s, int start, int before, int count) {
321 public void afterTextChanged(Editable s) {
322 // Get the new domain name.
323 String newDomainName = domainNameEditText.getText().toString();
325 // Check the saved SSL certificate against the new domain name.
326 boolean savedSslMatchesNewDomainName = checkDomainNameAgainstCertificate(newDomainName, savedSslIssuedToCNameString);
328 // Create a `SpannableStringBuilder` for the saved certificate `Common Name`.
329 SpannableStringBuilder savedSslCNameStringBuilder = new SpannableStringBuilder(cNameLabel + savedSslIssuedToCNameString);
331 // Format the saved certificate `Common Name` color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
332 if (savedSslMatchesNewDomainName) {
333 savedSslCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), savedSslCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
335 savedSslCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), savedSslCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
338 // Update the saved SSL issued to CName text view.
339 savedSslIssuedToCNameTextView.setText(savedSslCNameStringBuilder);
341 // Update the current website certificate if it exists.
342 if (DomainsActivity.sslIssuedToCName != null) {
343 // Check the current website certificate against the new domain name.
344 boolean currentSslMatchesNewDomainName = checkDomainNameAgainstCertificate(newDomainName, DomainsActivity.sslIssuedToCName);
346 // Create a `SpannableStringBuilder` for the current website certificate `Common Name`.
347 SpannableStringBuilder currentSslCNameStringBuilder = new SpannableStringBuilder(cNameLabel + DomainsActivity.sslIssuedToCName);
349 // Format the current certificate `Common Name` color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
350 if (currentSslMatchesNewDomainName) {
351 currentSslCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), currentSslCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
353 currentSslCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), currentSslCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
356 // Update the current SSL issued to CName text view.
357 currentSslIssuedToCNameTextView.setText(currentSslCNameStringBuilder);
362 // Create a boolean to track if night mode is enabled.
363 boolean nightModeEnabled = (nightModeInt == DomainsDatabaseHelper.ENABLED) || ((nightModeInt == DomainsDatabaseHelper.SYSTEM_DEFAULT) && defaultNightMode);
365 // Disable the JavaScript switch if night mode is enabled.
366 if (nightModeEnabled) {
367 javaScriptEnabledSwitch.setEnabled(false);
369 javaScriptEnabledSwitch.setEnabled(true);
372 // Set the JavaScript icon.
373 if ((javaScriptEnabledInt == 1) || nightModeEnabled) {
374 javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.javascript_enabled));
376 javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.privacy_mode));
379 // Set the JavaScript switch status.
380 if (javaScriptEnabledInt == 1) { // JavaScript is enabled.
381 javaScriptEnabledSwitch.setChecked(true);
382 } else { // JavaScript is disabled.
383 javaScriptEnabledSwitch.setChecked(false);
386 // 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.
387 if (firstPartyCookiesEnabledInt == 1) { // First-party cookies are enabled.
388 firstPartyCookiesEnabledSwitch.setChecked(true);
389 firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_enabled));
390 } else { // First-party cookies are disabled.
391 firstPartyCookiesEnabledSwitch.setChecked(false);
393 // Set the icon according to the theme.
395 firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_dark));
397 firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_light));
401 // Only display third-party cookies if SDK_INT >= 21.
402 if (Build.VERSION.SDK_INT >= 21) { // Third-party cookies can be configured for API >= 21.
403 // Only enable third-party-cookies if first-party cookies are enabled.
404 if (firstPartyCookiesEnabledInt == 1) { // First-party cookies are enabled.
405 // 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.
406 if (thirdPartyCookiesEnabledInt == 1) { // Both first-party and third-party cookies are enabled.
407 thirdPartyCookiesEnabledSwitch.setChecked(true);
408 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_warning));
409 } else { // First party cookies are enabled but third-party cookies are disabled.
410 thirdPartyCookiesEnabledSwitch.setChecked(false);
412 // Set the icon according to the theme.
414 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_dark));
416 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_light));
419 } else { // First-party cookies are disabled.
420 // Set the status of third-party cookies.
421 if (thirdPartyCookiesEnabledInt == 1) {
422 thirdPartyCookiesEnabledSwitch.setChecked(true);
424 thirdPartyCookiesEnabledSwitch.setChecked(false);
427 // Disable the third-party cookies switch.
428 thirdPartyCookiesEnabledSwitch.setEnabled(false);
430 // Set the icon according to the theme.
432 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_ghosted_dark));
434 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_ghosted_light));
437 } else { // Third-party cookies cannot be configured for API <= 21.
438 // Hide the LinearLayout for third-party cookies.
439 thirdPartyCookiesLinearLayout.setVisibility(View.GONE);
442 // Only enable DOM storage if JavaScript is enabled.
443 if ((javaScriptEnabledInt == 1) || nightModeEnabled) { // JavaScript is enabled.
444 // Enable the DOM storage `Switch`.
445 domStorageEnabledSwitch.setEnabled(true);
447 // Set the DOM storage status. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
448 if (domStorageEnabledInt == 1) { // Both JavaScript and DOM storage are enabled.
449 domStorageEnabledSwitch.setChecked(true);
450 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_enabled));
451 } else { // JavaScript is enabled but DOM storage is disabled.
452 // Set the DOM storage switch to off.
453 domStorageEnabledSwitch.setChecked(false);
455 // Set the icon according to the theme.
457 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_dark));
459 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_light));
462 } else { // JavaScript is disabled.
463 // Disable the DOM storage `Switch`.
464 domStorageEnabledSwitch.setEnabled(false);
466 // Set the checked status of DOM storage.
467 if (domStorageEnabledInt == 1) { // DOM storage is enabled but JavaScript is disabled.
468 domStorageEnabledSwitch.setChecked(true);
469 } else { // Both JavaScript and DOM storage are disabled.
470 domStorageEnabledSwitch.setChecked(false);
473 // Set the icon according to the theme.
475 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_dark));
477 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_light));
481 // 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.
482 if (Build.VERSION.SDK_INT >= 26) { // Form data no longer applies to newer versions of Android.
483 // Hide the form data switch.
484 formDataEnabledSwitch.setVisibility(View.GONE);
485 } else { // Form data should be displayed because this is an older version of Android.
486 if (formDataEnabledInt == 1) { // Form data is on.
487 formDataEnabledSwitch.setChecked(true);
488 formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_enabled));
489 } else { // Form data is off.
490 // Turn the form data switch to off.
491 formDataEnabledSwitch.setChecked(false);
493 // Set the icon according to the theme.
495 formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_disabled_dark));
497 formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_disabled_light));
502 // Set the EasyList status. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
503 if (easyListEnabledInt == 1) { // EasyList is on.
504 // Turn the switch on.
505 easyListSwitch.setChecked(true);
507 // Set the icon according to the theme.
509 easyListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_enabled_dark));
511 easyListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_enabled_light));
513 } else { // EasyList is off.
514 // Turn the switch off.
515 easyListSwitch.setChecked(false);
517 // Set the icon according to the theme.
519 easyListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_disabled_dark));
521 easyListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_disabled_light));
525 // Set the EasyPrivacy status. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
526 if (easyPrivacyEnabledInt == 1) { // EasyPrivacy is on.
527 // Turn the switch on.
528 easyPrivacySwitch.setChecked(true);
530 // Set the icon according to the theme.
532 easyPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_enabled_dark));
534 easyPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_enabled_light));
536 } else { // EasyPrivacy is off.
537 // Turn the switch off.
538 easyPrivacySwitch.setChecked(false);
540 // Set the icon according to the theme.
542 easyPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_disabled_dark));
544 easyPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_disabled_light));
548 // 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.
549 if (fanboysAnnoyanceListInt == 1) { // Fanboy's Annoyance List is on.
550 // Turn the switch on.
551 fanboysAnnoyanceListSwitch.setChecked(true);
553 // Set the icon according to the theme.
555 fanboysAnnoyanceListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_dark));
557 fanboysAnnoyanceListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_light));
559 } else { // Fanboy's Annoyance List is off.
560 // Turn the switch off.
561 fanboysAnnoyanceListSwitch.setChecked(false);
563 // Set the icon according to the theme.
565 fanboysAnnoyanceListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_dark));
567 fanboysAnnoyanceListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_light));
571 // Only enable Fanboy's Social Blocking List if Fanboy's Annoyance List is off.
572 if (fanboysAnnoyanceListInt == 0) { // Fanboy's Annoyance List is on.
573 // 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.
574 if (fanboysSocialBlockingListInt == 1) { // Fanboy's Social Blocking List is on.
575 // Enable the switch and turn it on.
576 fanboysSocialBlockingListSwitch.setEnabled(true);
577 fanboysSocialBlockingListSwitch.setChecked(true);
579 // Set the icon according to the theme.
581 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_dark));
583 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_light));
585 } else { // Fanboy's Social Blocking List is off.
586 // Enable the switch but turn it off.
587 fanboysSocialBlockingListSwitch.setEnabled(true);
588 fanboysSocialBlockingListSwitch.setChecked(false);
590 // Set the icon according to the theme.
592 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_dark));
594 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_light));
597 } else { // Fanboy's Annoyance List is on.
598 // 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.
599 if (fanboysSocialBlockingListInt == 1) { // Fanboy's Social Blocking List is on.
600 // Disable the switch but turn it on.
601 fanboysSocialBlockingListSwitch.setEnabled(false);
602 fanboysSocialBlockingListSwitch.setChecked(true);
603 } else { // Fanboy's Social Blocking List is off.
604 // Disable the switch and turn it off.
605 fanboysSocialBlockingListSwitch.setEnabled(false);
606 fanboysSocialBlockingListSwitch.setChecked(false);
609 // Set the icon according to the theme.
611 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_ghosted_dark));
613 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_ghosted_light));
617 // Set the UltraPrivacy status. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
618 if (ultraPrivacyEnabledInt == 1) { // UltraPrivacy is on.
619 // Turn the switch on.
620 ultraPrivacySwitch.setChecked(true);
622 // Set the icon according to the theme.
624 ultraPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_enabled_dark));
626 ultraPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_enabled_light));
628 } else { // EasyPrivacy is off.
629 // Turn the switch off.
630 ultraPrivacySwitch.setChecked(false);
632 // Set the icon according to the theme.
634 ultraPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_disabled_dark));
636 ultraPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_disabled_light));
640 // 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.
641 if (blockAllThirdPartyRequestsInt == 1) { // Blocking all third-party requests is on.
642 // Turn the switch on.
643 blockAllThirdPartyRequestsSwitch.setChecked(true);
645 // Set the icon according to the theme.
647 blockAllThirdPartyRequestsImageView.setImageDrawable(resources.getDrawable(R.drawable.block_all_third_party_requests_enabled_dark));
649 blockAllThirdPartyRequestsImageView.setImageDrawable(resources.getDrawable(R.drawable.block_all_third_party_requests_enabled_light));
651 } else { // Blocking all third-party requests is off.
652 // Turn the switch off.
653 blockAllThirdPartyRequestsSwitch.setChecked(false);
655 // Set the icon according to the theme.
657 blockAllThirdPartyRequestsImageView.setImageDrawable(resources.getDrawable(R.drawable.block_all_third_party_requests_disabled_dark));
659 blockAllThirdPartyRequestsImageView.setImageDrawable(resources.getDrawable(R.drawable.block_all_third_party_requests_disabled_light));
663 // Inflated a WebView to get the default user agent.
664 // `@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.
665 @SuppressLint("InflateParams") View bareWebViewLayout = inflater.inflate(R.layout.bare_webview, null, false);
666 WebView bareWebView = bareWebViewLayout.findViewById(R.id.bare_webview);
667 final String webViewDefaultUserAgentString = bareWebView.getSettings().getUserAgentString();
669 // Get a handle for the user agent array adapter. This array does not contain the `System default` entry.
670 ArrayAdapter<CharSequence> userAgentNamesArray = ArrayAdapter.createFromResource(context, R.array.user_agent_names, R.layout.spinner_item);
672 // Get the positions of the user agent and the default user agent.
673 int userAgentArrayPosition = userAgentNamesArray.getPosition(currentUserAgentName);
674 int defaultUserAgentArrayPosition = userAgentNamesArray.getPosition(defaultUserAgentName);
676 // Get a handle for the user agent data array. This array does not contain the `System default` entry.
677 String[] userAgentDataArray = resources.getStringArray(R.array.user_agent_data);
679 // Set the user agent text.
680 if (currentUserAgentName.equals(getString(R.string.system_default_user_agent))) { // Use the system default user agent.
681 // Set the user agent according to the system default.
682 switch (defaultUserAgentArrayPosition) {
683 case MainWebViewActivity.UNRECOGNIZED_USER_AGENT: // The default user agent name is not on the canonical list.
684 // This is probably because it was set in an older version of Privacy Browser before the switch to persistent user agent names.
685 userAgentTextView.setText(defaultUserAgentName);
688 case MainWebViewActivity.SETTINGS_WEBVIEW_DEFAULT_USER_AGENT:
689 // Display the `WebView` default user agent.
690 userAgentTextView.setText(webViewDefaultUserAgentString);
693 case MainWebViewActivity.SETTINGS_CUSTOM_USER_AGENT:
694 // Display the custom user agent.
695 userAgentTextView.setText(defaultCustomUserAgentString);
699 // Get the user agent string from the user agent data array.
700 userAgentTextView.setText(userAgentDataArray[defaultUserAgentArrayPosition]);
702 } else if (userAgentArrayPosition == MainWebViewActivity.UNRECOGNIZED_USER_AGENT) { // A custom user agent is stored in the current user agent name.
703 // Set the user agent spinner to `Custom user agent`.
704 userAgentSpinner.setSelection(MainWebViewActivity.DOMAINS_CUSTOM_USER_AGENT);
706 // Hide the user agent TextView.
707 userAgentTextView.setVisibility(View.GONE);
709 // Show the custom user agent EditText and set the current user agent name as the text.
710 customUserAgentEditText.setVisibility(View.VISIBLE);
711 customUserAgentEditText.setText(currentUserAgentName);
712 } else { // The user agent name contains one of the canonical user agents.
713 // 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.
714 userAgentSpinner.setSelection(userAgentArrayPosition + 1);
716 // Show the user agent TextView.
717 userAgentTextView.setVisibility(View.VISIBLE);
719 // Hide the custom user agent EditText.
720 customUserAgentEditText.setVisibility(View.GONE);
722 // Set the user agent text.
723 if (userAgentArrayPosition == MainWebViewActivity.DOMAINS_WEBVIEW_DEFAULT_USER_AGENT) { // The WebView default user agent is selected.
724 // Display the WebView default user agent.
725 userAgentTextView.setText(webViewDefaultUserAgentString);
726 } else { // A user agent besides the default is selected.
727 // Get the user agent string from the user agent data array. The spinner has one more entry at the beginning than the user agent data array, so the position must be incremented.
728 userAgentTextView.setText(userAgentDataArray[userAgentArrayPosition + 1]);
732 // Open the user agent spinner when the text view is clicked.
733 userAgentTextView.setOnClickListener((View v) -> {
734 // Open the user agent spinner.
735 userAgentSpinner.performClick();
738 // Set the selected font size.
739 int fontSizeArrayPosition = fontSizeEntryValuesArrayAdapter.getPosition(String.valueOf(fontSizeInt));
740 fontSizeSpinner.setSelection(fontSizeArrayPosition);
742 // Set the default font size text.
743 int defaultFontSizeArrayPosition = fontSizeEntryValuesArrayAdapter.getPosition(defaultFontSizeString);
744 fontSizeTextView.setText(fontSizeArrayAdapter.getItem(defaultFontSizeArrayPosition));
746 // Set the display options for the font size TextView.
747 if (fontSizeArrayPosition == 0) { // System default font size is selected. Display `fontSizeTextView`.
748 fontSizeTextView.setVisibility(View.VISIBLE);
749 } else { // A custom font size is specified. Hide `fontSizeTextView`.
750 fontSizeTextView.setVisibility(View.GONE);
753 // Open the font size spinner when the TextView is clicked.
754 fontSizeTextView.setOnClickListener((View v) -> {
755 // Open the user agent spinner.
756 fontSizeSpinner.performClick();
759 // Display the swipe to refresh selection in the spinner.
760 swipeToRefreshSpinner.setSelection(swipeToRefreshInt);
762 // Set the swipe to refresh text.
763 if (defaultSwipeToRefresh) {
764 swipeToRefreshTextView.setText(swipeToRefreshArrayAdapter.getItem(DomainsDatabaseHelper.ENABLED));
766 swipeToRefreshTextView.setText(swipeToRefreshArrayAdapter.getItem(DomainsDatabaseHelper.DISABLED));
769 // Set the swipe to refresh icon and TextView settings. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
770 switch (swipeToRefreshInt) {
771 case DomainsDatabaseHelper.SYSTEM_DEFAULT:
772 if (defaultSwipeToRefresh) { // Swipe to refresh is enabled by default.
773 // Set the icon according to the theme.
775 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_enabled_dark));
777 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_enabled_light));
779 } else { // Swipe to refresh is disabled by default
780 // Set the icon according to the theme.
782 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_disabled_dark));
784 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_disabled_light));
788 // Show the swipe to refresh TextView.
789 swipeToRefreshTextView.setVisibility(View.VISIBLE);
792 case DomainsDatabaseHelper.ENABLED:
793 // Set the icon according to the theme.
795 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_enabled_dark));
797 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_enabled_light));
800 // Hide the swipe to refresh TextView.`
801 swipeToRefreshTextView.setVisibility(View.GONE);
804 case DomainsDatabaseHelper.DISABLED:
805 // Set the icon according to the theme.
807 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_disabled_dark));
809 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_disabled_light));
812 // Hide the swipe to refresh TextView.
813 swipeToRefreshTextView.setVisibility(View.GONE);
816 // Open the swipe to refresh spinner when the TextView is clicked.
817 swipeToRefreshTextView.setOnClickListener((View v) -> {
818 // Open the swipe to refresh spinner.
819 swipeToRefreshSpinner.performClick();
822 // Display the night mode in the spinner.
823 nightModeSpinner.setSelection(nightModeInt);
825 // Set the default night mode text.
826 if (defaultNightMode) {
827 nightModeTextView.setText(nightModeArrayAdapter.getItem(DomainsDatabaseHelper.ENABLED));
829 nightModeTextView.setText(nightModeArrayAdapter.getItem(DomainsDatabaseHelper.DISABLED));
832 // Set the night mode icon and TextView settings. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
833 switch (nightModeInt) {
834 case DomainsDatabaseHelper.SYSTEM_DEFAULT:
835 if (defaultNightMode) { // Night mode enabled by default.
836 // Set the icon according to the theme.
838 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_dark));
840 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_light));
842 } else { // Night mode disabled by default.
843 // Set the icon according to the theme.
845 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_dark));
847 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_light));
851 // Show night mode TextView.
852 nightModeTextView.setVisibility(View.VISIBLE);
855 case DomainsDatabaseHelper.ENABLED:
856 // Set the icon according to the theme.
858 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_dark));
860 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_light));
863 // Hide the night mode TextView.
864 nightModeTextView.setVisibility(View.GONE);
867 case DomainsDatabaseHelper.DISABLED:
868 // Set the icon according to the theme.
870 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_dark));
872 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_light));
875 // Hide the night mode TextView.
876 nightModeTextView.setVisibility(View.GONE);
880 // Open the night mode spinner when the TextView is clicked.
881 nightModeTextView.setOnClickListener((View v) -> {
882 // Open the night mode spinner.
883 nightModeSpinner.performClick();
886 // Display the wide viewport in the spinner.
887 wideViewportSpinner.setSelection(wideViewportInt);
889 // Set the default wide viewport text.
890 if (defaultWideViewport) {
891 wideViewportTextView.setText(wideViewportArrayAdapter.getItem(DomainsDatabaseHelper.ENABLED));
893 wideViewportTextView.setText(wideViewportArrayAdapter.getItem(DomainsDatabaseHelper.DISABLED));
896 // Set the wide viewport icon and text view settings. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
897 switch (wideViewportInt) {
898 case DomainsDatabaseHelper.SYSTEM_DEFAULT:
899 if (defaultWideViewport) { // Wide viewport enabled by default.
900 // Set the icon according to the theme.
902 wideViewportImageView.setImageDrawable(resources.getDrawable(R.drawable.wide_viewport_enabled_dark));
904 wideViewportImageView.setImageDrawable(resources.getDrawable(R.drawable.wide_viewport_enabled_light));
906 } else { // Wide viewport disabled by default.
908 wideViewportImageView.setImageDrawable(resources.getDrawable(R.drawable.wide_viewport_disabled_dark));
910 wideViewportImageView.setImageDrawable(resources.getDrawable(R.drawable.wide_viewport_disabled_light));
914 // Show the wide viewport text view.
915 wideViewportTextView.setVisibility(View.VISIBLE);
918 case DomainsDatabaseHelper.ENABLED:
919 // Set the icon according to the theme.
921 wideViewportImageView.setImageDrawable(resources.getDrawable(R.drawable.wide_viewport_enabled_dark));
923 wideViewportImageView.setImageDrawable(resources.getDrawable(R.drawable.wide_viewport_enabled_light));
926 // Hide the wide viewport text view.
927 wideViewportTextView.setVisibility(View.GONE);
930 case DomainsDatabaseHelper.DISABLED:
931 // Set the icon according to the theme.
933 wideViewportImageView.setImageDrawable(resources.getDrawable(R.drawable.wide_viewport_disabled_dark));
935 wideViewportImageView.setImageDrawable(resources.getDrawable(R.drawable.wide_viewport_disabled_light));
938 // Hide the wide viewport text view.
939 wideViewportTextView.setVisibility(View.GONE);
943 // Open the wide viewport spinner when the text view is clicked.
944 wideViewportTextView.setOnClickListener((View view) -> {
945 // Open the wide viewport spinner.
946 wideViewportSpinner.performClick();
949 // Display the website images mode in the spinner.
950 displayWebpageImagesSpinner.setSelection(displayImagesInt);
952 // Set the default display images text.
953 if (defaultDisplayWebpageImages) {
954 displayImagesTextView.setText(displayImagesArrayAdapter.getItem(DomainsDatabaseHelper.ENABLED));
956 displayImagesTextView.setText(displayImagesArrayAdapter.getItem(DomainsDatabaseHelper.DISABLED));
959 // Set the display website images icon and text view settings. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
960 switch (displayImagesInt) {
961 case DomainsDatabaseHelper.SYSTEM_DEFAULT:
962 if (defaultDisplayWebpageImages) { // Display webpage images enabled by default.
963 // Set the icon according to the theme.
965 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_dark));
967 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_light));
969 } else { // Display webpage images disabled by default.
970 // Set the icon according to the theme.
972 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_dark));
974 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_light));
978 // Show the display images text view.
979 displayImagesTextView.setVisibility(View.VISIBLE);
982 case DomainsDatabaseHelper.ENABLED:
983 // Set the icon according to the theme.
985 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_dark));
987 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_light));
990 // Hide the display images text view.
991 displayImagesTextView.setVisibility(View.GONE);
994 case DomainsDatabaseHelper.DISABLED:
995 // Set the icon according to the theme.
997 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_dark));
999 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_light));
1002 // Hide the display images text view.
1003 displayImagesTextView.setVisibility(View.GONE);
1007 // Open the display images spinner when the text view is clicked.
1008 displayImagesTextView.setOnClickListener((View view) -> {
1009 // Open the user agent spinner.
1010 displayWebpageImagesSpinner.performClick();
1013 // Set the pinned SSL certificate icon.
1014 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.
1015 // Check the switch.
1016 pinnedSslCertificateSwitch.setChecked(true);
1018 // Set the icon according to the theme.
1020 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_dark));
1022 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_light));
1024 } else { // Pinned SSL certificate is disabled.
1025 // Uncheck the switch.
1026 pinnedSslCertificateSwitch.setChecked(false);
1028 // Set the icon according to the theme.
1030 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_dark));
1032 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_light));
1036 // Store the current date.
1037 Date currentDate = Calendar.getInstance().getTime();
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 savedSslIssuedToONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), savedSslIssuedToONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1041 savedSslIssuedToUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), savedSslIssuedToUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1042 savedSslIssuedByCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), savedSslIssuedByCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1043 savedSslIssuedByONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), savedSslIssuedByONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1044 savedSslIssuedByUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), savedSslIssuedByUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1046 // Check the certificate Common Name against the domain name.
1047 boolean savedSslCommonNameMatchesDomainName = checkDomainNameAgainstCertificate(domainNameString, savedSslIssuedToCNameString);
1049 // Format the issued to Common Name color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
1050 if (savedSslCommonNameMatchesDomainName) {
1051 savedSslIssuedToCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), savedSslIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1053 savedSslIssuedToCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), savedSslIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1056 // Format the start date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
1057 if ((savedSslStartDate != null) && savedSslStartDate.after(currentDate)) { // The certificate start date is in the future.
1058 savedSslStartDateStringBuilder.setSpan(redColorSpan, startDateLabel.length(), savedSslStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1059 } else { // The certificate start date is in the past.
1060 savedSslStartDateStringBuilder.setSpan(blueColorSpan, startDateLabel.length(), savedSslStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1063 // Format the end date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
1064 if ((savedSslEndDate != null) && savedSslEndDate.before(currentDate)) { // The certificate end date is in the past.
1065 savedSslEndDateStringBuilder.setSpan(redColorSpan, endDateLabel.length(), savedSslEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1066 } else { // The certificate end date is in the future.
1067 savedSslEndDateStringBuilder.setSpan(blueColorSpan, endDateLabel.length(), savedSslEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1070 // Display the saved website SSL certificate strings.
1071 savedSslIssuedToCNameTextView.setText(savedSslIssuedToCNameStringBuilder);
1072 savedSslIssuedToONameTextView.setText(savedSslIssuedToONameStringBuilder);
1073 savedSslIssuedToUNameTextView.setText(savedSslIssuedToUNameStringBuilder);
1074 savedSslIssuedByCNameTextView.setText(savedSslIssuedByCNameStringBuilder);
1075 savedSslIssuedByONameTextView.setText(savedSslIssuedByONameStringBuilder);
1076 savedSslIssuedByUNameTextView.setText(savedSslIssuedByUNameStringBuilder);
1077 savedSslStartDateTextView.setText(savedSslStartDateStringBuilder);
1078 savedSslEndDateTextView.setText(savedSslEndDateStringBuilder);
1080 // Populate the current website SSL certificate if there is one.
1081 if (DomainsActivity.sslIssuedToCName != null) {
1082 // Get dates from the raw long values.
1083 Date currentSslStartDate = new Date(DomainsActivity.sslStartDateLong);
1084 Date currentSslEndDate = new Date(DomainsActivity.sslEndDateLong);
1086 // Create a spannable string builder for each text view that needs multiple colors of text.
1087 SpannableStringBuilder currentSslIssuedToCNameStringBuilder = new SpannableStringBuilder(cNameLabel + DomainsActivity.sslIssuedToCName);
1088 SpannableStringBuilder currentSslIssuedToONameStringBuilder = new SpannableStringBuilder(oNameLabel + DomainsActivity.sslIssuedToOName);
1089 SpannableStringBuilder currentSslIssuedToUNameStringBuilder = new SpannableStringBuilder(uNameLabel + DomainsActivity.sslIssuedToUName);
1090 SpannableStringBuilder currentSslIssuedByCNameStringBuilder = new SpannableStringBuilder(cNameLabel + DomainsActivity.sslIssuedByCName);
1091 SpannableStringBuilder currentSslIssuedByONameStringBuilder = new SpannableStringBuilder(oNameLabel + DomainsActivity.sslIssuedByOName);
1092 SpannableStringBuilder currentSslIssuedByUNameStringBuilder = new SpannableStringBuilder(uNameLabel + DomainsActivity.sslIssuedByUName);
1093 SpannableStringBuilder currentSslStartDateStringBuilder = new SpannableStringBuilder(startDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG)
1094 .format(currentSslStartDate));
1095 SpannableStringBuilder currentSslEndDateStringBuilder = new SpannableStringBuilder(endDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG)
1096 .format(currentSslEndDate));
1098 // Setup the string builders to display the general certificate information in blue. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
1099 currentSslIssuedToONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), currentSslIssuedToONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1100 currentSslIssuedToUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), currentSslIssuedToUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1101 currentSslIssuedByCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), currentSslIssuedByCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1102 currentSslIssuedByONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), currentSslIssuedByONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1103 currentSslIssuedByUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), currentSslIssuedByUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1105 // Check the certificate Common Name against the domain name.
1106 boolean currentSslCommonNameMatchesDomainName = checkDomainNameAgainstCertificate(domainNameString, DomainsActivity.sslIssuedToCName);
1108 // Format the issued to Common Name color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
1109 if (currentSslCommonNameMatchesDomainName) {
1110 currentSslIssuedToCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), currentSslIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1112 currentSslIssuedToCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), currentSslIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1115 // Format the start date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
1116 if (currentSslStartDate.after(currentDate)) { // The certificate start date is in the future.
1117 currentSslStartDateStringBuilder.setSpan(redColorSpan, startDateLabel.length(), currentSslStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1118 } else { // The certificate start date is in the past.
1119 currentSslStartDateStringBuilder.setSpan(blueColorSpan, startDateLabel.length(), currentSslStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1122 // Format the end date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
1123 if (currentSslEndDate.before(currentDate)) { // The certificate end date is in the past.
1124 currentSslEndDateStringBuilder.setSpan(redColorSpan, endDateLabel.length(), currentSslEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1125 } else { // The certificate end date is in the future.
1126 currentSslEndDateStringBuilder.setSpan(blueColorSpan, endDateLabel.length(), currentSslEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1129 // Display the current website SSL certificate strings.
1130 currentSslIssuedToCNameTextView.setText(currentSslIssuedToCNameStringBuilder);
1131 currentSslIssuedToONameTextView.setText(currentSslIssuedToONameStringBuilder);
1132 currentSslIssuedToUNameTextView.setText(currentSslIssuedToUNameStringBuilder);
1133 currentSslIssuedByCNameTextView.setText(currentSslIssuedByCNameStringBuilder);
1134 currentSslIssuedByONameTextView.setText(currentSslIssuedByONameStringBuilder);
1135 currentSslIssuedByUNameTextView.setText(currentSslIssuedByUNameStringBuilder);
1136 currentSslStartDateTextView.setText(currentSslStartDateStringBuilder);
1137 currentSslEndDateTextView.setText(currentSslEndDateStringBuilder);
1140 // Set the initial display status of the SSL certificates card views.
1141 if (pinnedSslCertificateSwitch.isChecked()) { // An SSL certificate is pinned.
1142 // Set the visibility of the saved SSL certificate.
1143 if (savedSslIssuedToCNameString == null) {
1144 savedSslCardView.setVisibility(View.GONE);
1146 savedSslCardView.setVisibility(View.VISIBLE);
1149 // Set the visibility of the current website SSL certificate.
1150 if (DomainsActivity.sslIssuedToCName == null) { // There is no current SSL certificate.
1151 // Hide the SSL certificate.
1152 currentSslCardView.setVisibility(View.GONE);
1154 // Show the instruction.
1155 noCurrentWebsiteCertificateTextView.setVisibility(View.VISIBLE);
1156 } else { // There is a current SSL certificate.
1157 // Show the SSL certificate.
1158 currentSslCardView.setVisibility(View.VISIBLE);
1160 // Hide the instruction.
1161 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
1164 // Set the status of the radio buttons and the card view backgrounds.
1165 if (savedSslCardView.getVisibility() == View.VISIBLE) { // The saved SSL certificate is displayed.
1166 // Check the saved SSL certificate radio button.
1167 savedSslCertificateRadioButton.setChecked(true);
1169 // Uncheck the current website SSL certificate radio button.
1170 currentWebsiteCertificateRadioButton.setChecked(false);
1172 // Darken the background of the current website SSL certificate linear layout according to the theme.
1174 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1176 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1178 } else if (currentSslCardView.getVisibility() == View.VISIBLE) { // The saved SSL certificate is hidden but the current website SSL certificate is visible.
1179 // Check the current website SSL certificate radio button.
1180 currentWebsiteCertificateRadioButton.setChecked(true);
1182 // Uncheck the saved SSL certificate radio button.
1183 savedSslCertificateRadioButton.setChecked(false);
1184 } else { // Neither SSL certificate is visible.
1185 // Uncheck both radio buttons.
1186 savedSslCertificateRadioButton.setChecked(false);
1187 currentWebsiteCertificateRadioButton.setChecked(false);
1189 } else { // An SSL certificate is not pinned.
1190 // Hide the SSl certificates and instructions.
1191 savedSslCardView.setVisibility(View.GONE);
1192 currentSslCardView.setVisibility(View.GONE);
1193 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
1195 // Uncheck the radio buttons.
1196 savedSslCertificateRadioButton.setChecked(false);
1197 currentWebsiteCertificateRadioButton.setChecked(false);
1200 // Set the pinned IP addresses icon.
1201 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.
1202 // Check the switch.
1203 pinnedIpAddressesSwitch.setChecked(true);
1205 // Set the icon according to the theme.
1207 pinnedIpAddressesImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_dark));
1209 pinnedIpAddressesImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_light));
1211 } else { // Pinned IP Addresses is disabled.
1212 // Uncheck the switch.
1213 pinnedIpAddressesSwitch.setChecked(false);
1215 // Set the icon according to the theme.
1217 pinnedIpAddressesImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_dark));
1219 pinnedIpAddressesImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_light));
1223 // Populate the saved and current IP addresses.
1224 savedIpAddressesTextView.setText(savedIpAddresses);
1225 currentIpAddressesTextView.setText(DomainsActivity.currentIpAddresses);
1227 // Set the initial display status of the IP addresses card views.
1228 if (pinnedIpAddressesSwitch.isChecked()) { // IP addresses are pinned.
1229 // Set the visibility of the saved IP addresses.
1230 if (savedIpAddresses == null) { // There are no saved IP addresses.
1231 savedIpAddressesCardView.setVisibility(View.GONE);
1232 } else { // There are saved IP addresses.
1233 savedIpAddressesCardView.setVisibility(View.VISIBLE);
1236 // Set the visibility of the current IP addresses.
1237 currentIpAddressesCardView.setVisibility(View.VISIBLE);
1239 // Set the status of the radio buttons and the card view backgrounds.
1240 if (savedIpAddressesCardView.getVisibility() == View.VISIBLE) { // The saved IP addresses are displayed.
1241 // Check the saved IP addresses radio button.
1242 savedIpAddressesRadioButton.setChecked(true);
1244 // Uncheck the current IP addresses radio button.
1245 currentIpAddressesRadioButton.setChecked(false);
1247 // Darken the background of the current IP addresses linear layout according to the theme.
1249 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1251 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1253 } else { // The saved IP addresses are hidden.
1254 // Check the current IP addresses radio button.
1255 currentIpAddressesRadioButton.setChecked(true);
1257 // Uncheck the saved IP addresses radio button.
1258 savedIpAddressesRadioButton.setChecked(false);
1260 } else { // IP addresses are not pinned.
1261 // Hide the IP addresses card views.
1262 savedIpAddressesCardView.setVisibility(View.GONE);
1263 currentIpAddressesCardView.setVisibility(View.GONE);
1265 // Uncheck the radio buttons.
1266 savedIpAddressesRadioButton.setChecked(false);
1267 currentIpAddressesRadioButton.setChecked(false);
1271 // Set the JavaScript switch listener.
1272 javaScriptEnabledSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1273 if (isChecked) { // JavaScript is enabled.
1274 // Update the JavaScript icon.
1275 javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.javascript_enabled));
1277 // Enable the DOM storage `Switch`.
1278 domStorageEnabledSwitch.setEnabled(true);
1280 // Update the DOM storage icon.
1281 if (domStorageEnabledSwitch.isChecked()) { // DOM storage is enabled.
1282 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_enabled));
1283 } else { // DOM storage is disabled.
1284 // Set the icon according to the theme.
1286 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_dark));
1288 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_light));
1291 } else { // JavaScript is disabled.
1292 // Update the JavaScript icon.
1293 javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.privacy_mode));
1295 // Disable the DOM storage `Switch`.
1296 domStorageEnabledSwitch.setEnabled(false);
1298 // Set the DOM storage icon according to the theme.
1300 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_dark));
1302 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_light));
1307 // Set the first-party cookies switch listener.
1308 firstPartyCookiesEnabledSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1309 if (isChecked) { // First-party cookies are enabled.
1310 // Update the first-party cookies icon.
1311 firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_enabled));
1313 // Enable the third-party cookies switch.
1314 thirdPartyCookiesEnabledSwitch.setEnabled(true);
1316 // Update the third-party cookies icon.
1317 if (thirdPartyCookiesEnabledSwitch.isChecked()) { // Third-party cookies are enabled.
1318 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_warning));
1319 } else { // Third-party cookies are disabled.
1320 // Set the third-party cookies icon according to the theme.
1322 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_dark));
1324 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_light));
1327 } else { // First-party cookies are disabled.
1328 // Update the first-party cookies icon according to the theme.
1330 firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_dark));
1332 firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_light));
1335 // Disable the third-party cookies switch.
1336 thirdPartyCookiesEnabledSwitch.setEnabled(false);
1338 // Set the third-party cookies icon according to the theme.
1340 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_ghosted_dark));
1342 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_ghosted_light));
1347 // Set the third-party cookies switch listener.
1348 thirdPartyCookiesEnabledSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1351 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_warning));
1353 // Update the third-party cookies icon according to the theme.
1355 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_dark));
1357 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_light));
1362 // Set the DOM Storage switch listener.
1363 domStorageEnabledSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1366 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_enabled));
1368 // Set the icon according to the theme.
1370 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_dark));
1372 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_light));
1377 // Set the form data switch listener. It can be removed once the minimum API >= 26.
1378 if (Build.VERSION.SDK_INT < 26) {
1379 formDataEnabledSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1382 formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_enabled));
1384 // Set the icon according to the theme.
1386 formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_disabled_dark));
1388 formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_disabled_light));
1394 // Set the EasyList switch listener.
1395 easyListSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1397 if (isChecked) { // EasyList is on.
1398 // Set the icon according to the theme.
1400 easyListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_enabled_dark));
1402 easyListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_enabled_light));
1404 } else { // EasyList is off.
1405 // Set the icon according to the theme.
1407 easyListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_disabled_dark));
1409 easyListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_disabled_light));
1414 // Set the EasyPrivacy switch listener.
1415 easyPrivacySwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1417 if (isChecked) { // EasyPrivacy is on.
1418 // Set the icon according to the theme.
1420 easyPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_enabled_dark));
1422 easyPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_enabled_light));
1424 } else { // EasyPrivacy is off.
1425 // Set the icon according to the theme.
1427 easyPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_disabled_dark));
1429 easyPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_disabled_light));
1434 // Set the Fanboy's Annoyance List switch listener.
1435 fanboysAnnoyanceListSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1436 // Update the icon and Fanboy's Social Blocking List.
1437 if (isChecked) { // Fanboy's Annoyance List is on.
1438 // Set the icon according to the theme.
1440 fanboysAnnoyanceListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_dark));
1442 fanboysAnnoyanceListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_light));
1445 // Disable the Fanboy's Social Blocking List switch.
1446 fanboysSocialBlockingListSwitch.setEnabled(false);
1448 // Update the Fanboy's Social Blocking List icon according to the theme.
1450 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_ghosted_dark));
1452 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_ghosted_light));
1454 } else { // Fanboy's Annoyance List is off.
1455 // Set the icon according to the theme.
1457 fanboysAnnoyanceListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_dark));
1459 fanboysAnnoyanceListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_light));
1462 // Enable the Fanboy's Social Blocking List switch.
1463 fanboysSocialBlockingListSwitch.setEnabled(true);
1465 // Update the Fanboy's Social Blocking List icon.
1466 if (fanboysSocialBlockingListSwitch.isChecked()) { // Fanboy's Social Blocking List is on.
1467 // Update the icon according to the theme.
1469 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_dark));
1471 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_light));
1473 } else { // Fanboy's Social Blocking List is off.
1474 // Update the icon according to the theme.
1476 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_dark));
1478 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_light));
1485 // Set the Fanboy's Social Blocking List switch listener.
1486 fanboysSocialBlockingListSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1488 if (isChecked) { // Fanboy's Social Blocking List is on.
1489 // Set the icon according to the theme.
1491 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_dark));
1493 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_light));
1495 } else { // Fanboy's Social Blocking List is off.
1496 // Set the icon according to the theme.
1498 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_dark));
1500 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_light));
1505 // Set the UltraPrivacy switch listener.
1506 ultraPrivacySwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1508 if (isChecked) { // UltraPrivacy is on.
1509 // Set the icon according to the theme.
1511 ultraPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_enabled_dark));
1513 ultraPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_enabled_light));
1515 } else { // UltraPrivacy is off.
1516 // Set the icon according to the theme.
1518 ultraPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_disabled_dark));
1520 ultraPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_disabled_light));
1525 // Set the block all third-party requests switch listener.
1526 blockAllThirdPartyRequestsSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1528 if (isChecked) { // Blocking all third-party requests is on.
1529 // Set the icon according to the theme.
1531 blockAllThirdPartyRequestsImageView.setImageDrawable(resources.getDrawable(R.drawable.block_all_third_party_requests_enabled_dark));
1533 blockAllThirdPartyRequestsImageView.setImageDrawable(resources.getDrawable(R.drawable.block_all_third_party_requests_enabled_light));
1535 } else { // Blocking all third-party requests is off.
1536 // Set the icon according to the theme.
1538 blockAllThirdPartyRequestsImageView.setImageDrawable(resources.getDrawable(R.drawable.block_all_third_party_requests_disabled_dark));
1540 blockAllThirdPartyRequestsImageView.setImageDrawable(resources.getDrawable(R.drawable.block_all_third_party_requests_disabled_light));
1545 // Set the user agent spinner listener.
1546 userAgentSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1548 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1549 // Set the new user agent.
1551 case MainWebViewActivity.DOMAINS_SYSTEM_DEFAULT_USER_AGENT:
1552 // Show the user agent TextView.
1553 userAgentTextView.setVisibility(View.VISIBLE);
1555 // Hide the custom user agent EditText.
1556 customUserAgentEditText.setVisibility(View.GONE);
1558 // Set the user text.
1559 switch (defaultUserAgentArrayPosition) {
1560 case MainWebViewActivity.UNRECOGNIZED_USER_AGENT: // The default user agent name is not on the canonical list.
1561 // This is probably because it was set in an older version of Privacy Browser before the switch to persistent user agent names.
1562 userAgentTextView.setText(defaultUserAgentName);
1565 case MainWebViewActivity.SETTINGS_WEBVIEW_DEFAULT_USER_AGENT:
1566 // Display the `WebView` default user agent.
1567 userAgentTextView.setText(webViewDefaultUserAgentString);
1570 case MainWebViewActivity.SETTINGS_CUSTOM_USER_AGENT:
1571 // Display the custom user agent.
1572 userAgentTextView.setText(defaultCustomUserAgentString);
1576 // Get the user agent string from the user agent data array.
1577 userAgentTextView.setText(userAgentDataArray[defaultUserAgentArrayPosition]);
1581 case MainWebViewActivity.DOMAINS_WEBVIEW_DEFAULT_USER_AGENT:
1582 // Show the user agent TextView and set the text.
1583 userAgentTextView.setVisibility(View.VISIBLE);
1584 userAgentTextView.setText(webViewDefaultUserAgentString);
1586 // Hide the custom user agent EditTex.
1587 customUserAgentEditText.setVisibility(View.GONE);
1590 case MainWebViewActivity.DOMAINS_CUSTOM_USER_AGENT:
1591 // Hide the user agent TextView.
1592 userAgentTextView.setVisibility(View.GONE);
1594 // Show the custom user agent EditText and set the current user agent name as the text.
1595 customUserAgentEditText.setVisibility(View.VISIBLE);
1596 customUserAgentEditText.setText(currentUserAgentName);
1600 // 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.
1601 userAgentTextView.setVisibility(View.VISIBLE);
1602 userAgentTextView.setText(userAgentDataArray[position - 1]);
1604 // Hide `customUserAgentEditText`.
1605 customUserAgentEditText.setVisibility(View.GONE);
1610 public void onNothingSelected(AdapterView<?> parent) {
1615 // Set the font size spinner listener.
1616 fontSizeSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1618 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1619 // Update the display options for `fontSizeTextView`.
1620 if (position == 0) { // System default font size has been selected. Display `fontSizeTextView`.
1621 fontSizeTextView.setVisibility(View.VISIBLE);
1622 } else { // A custom font size has been selected. Hide `fontSizeTextView`.
1623 fontSizeTextView.setVisibility(View.GONE);
1628 public void onNothingSelected(AdapterView<?> parent) {
1633 // Set the swipe to refresh spinner listener.
1634 swipeToRefreshSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1636 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1637 // 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.
1639 case DomainsDatabaseHelper.SYSTEM_DEFAULT:
1640 if (defaultSwipeToRefresh) { // Swipe to refresh enabled by default.
1641 // Set the icon according to the theme.
1643 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_enabled_dark));
1645 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_enabled_light));
1647 } else { // Swipe to refresh disabled by default.
1648 // Set the icon according to the theme.
1650 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_disabled_dark));
1652 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_disabled_light));
1656 // Show the swipe to refresh TextView.
1657 swipeToRefreshTextView.setVisibility(View.VISIBLE);
1660 case DomainsDatabaseHelper.ENABLED:
1661 // Set the icon according to the theme.
1663 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_enabled_dark));
1665 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_enabled_light));
1668 // Hide the swipe to refresh TextView.
1669 swipeToRefreshTextView.setVisibility(View.GONE);
1672 case DomainsDatabaseHelper.DISABLED:
1673 // Set the icon according to the theme.
1675 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_disabled_dark));
1677 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_disabled_light));
1680 // Hide the swipe to refresh TextView.
1681 swipeToRefreshTextView.setVisibility(View.GONE);
1686 public void onNothingSelected(AdapterView<?> parent) {
1691 // Set the night mode spinner listener.
1692 nightModeSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1694 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1695 // 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.
1697 case DomainsDatabaseHelper.SYSTEM_DEFAULT:
1698 if (defaultNightMode) { // Night mode enabled by default.
1699 // Set the icon according to the theme.
1701 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_dark));
1703 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_light));
1705 } else { // Night mode disabled by default.
1706 // Set the icon according to the theme.
1708 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_dark));
1710 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_light));
1714 // Show the night mode TextView.
1715 nightModeTextView.setVisibility(View.VISIBLE);
1718 case DomainsDatabaseHelper.ENABLED:
1719 // Set the icon according to the theme.
1721 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_dark));
1723 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_light));
1726 // Hide `nightModeTextView`.
1727 nightModeTextView.setVisibility(View.GONE);
1730 case DomainsDatabaseHelper.DISABLED:
1731 // Set the icon according to the theme.
1733 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_dark));
1735 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_light));
1738 // Hide `nightModeTextView`.
1739 nightModeTextView.setVisibility(View.GONE);
1743 // Create a `boolean` to store the current night mode setting.
1744 boolean currentNightModeEnabled = (position == DomainsDatabaseHelper.ENABLED) || ((position == DomainsDatabaseHelper.SYSTEM_DEFAULT) && defaultNightMode);
1746 // Disable the JavaScript `Switch` if night mode is enabled.
1747 if (currentNightModeEnabled) {
1748 javaScriptEnabledSwitch.setEnabled(false);
1750 javaScriptEnabledSwitch.setEnabled(true);
1753 // Update the JavaScript icon.
1754 if ((javaScriptEnabledInt == 1) || currentNightModeEnabled) {
1755 javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.javascript_enabled));
1757 javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.privacy_mode));
1760 // Update the DOM storage status.
1761 if ((javaScriptEnabledInt == 1) || currentNightModeEnabled) { // JavaScript is enabled.
1762 // Enable the DOM storage `Switch`.
1763 domStorageEnabledSwitch.setEnabled(true);
1765 // Set the DOM storage status. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
1766 if (domStorageEnabledInt == 1) { // Both JavaScript and DOM storage are enabled.
1767 domStorageEnabledSwitch.setChecked(true);
1768 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_enabled));
1769 } else { // JavaScript is enabled but DOM storage is disabled.
1770 // Set the DOM storage switch to off.
1771 domStorageEnabledSwitch.setChecked(false);
1773 // Set the icon according to the theme.
1775 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_dark));
1777 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_light));
1780 } else { // JavaScript is disabled.
1781 // Disable the DOM storage `Switch`.
1782 domStorageEnabledSwitch.setEnabled(false);
1784 // Set the checked status of DOM storage.
1785 if (domStorageEnabledInt == 1) { // DOM storage is enabled but JavaScript is disabled.
1786 domStorageEnabledSwitch.setChecked(true);
1787 } else { // Both JavaScript and DOM storage are disabled.
1788 domStorageEnabledSwitch.setChecked(false);
1791 // Set the icon according to the theme.
1793 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_dark));
1795 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_light));
1801 public void onNothingSelected(AdapterView<?> parent) {
1806 // Set the wide viewport spinner listener.
1807 wideViewportSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1809 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1810 // Update the icon and the visibility of the wide viewport text view.
1812 case DomainsDatabaseHelper.SYSTEM_DEFAULT:
1813 if (defaultWideViewport) { // Wide viewport is enabled by default.
1814 // Set the icon according to the theme.
1816 wideViewportImageView.setImageDrawable(resources.getDrawable(R.drawable.wide_viewport_enabled_dark));
1818 wideViewportImageView.setImageDrawable(resources.getDrawable(R.drawable.wide_viewport_enabled_light));
1820 } else { // Wide viewport is disabled by default.
1822 wideViewportImageView.setImageDrawable(resources.getDrawable(R.drawable.wide_viewport_disabled_dark));
1824 wideViewportImageView.setImageDrawable(resources.getDrawable(R.drawable.wide_viewport_disabled_light));
1828 // Show the wide viewport text view.
1829 wideViewportTextView.setVisibility(View.VISIBLE);
1832 case DomainsDatabaseHelper.ENABLED:
1833 // Set the icon according to the theme.
1835 wideViewportImageView.setImageDrawable(resources.getDrawable(R.drawable.wide_viewport_enabled_dark));
1837 wideViewportImageView.setImageDrawable(resources.getDrawable(R.drawable.wide_viewport_enabled_light));
1840 // Hide the wide viewport text view.
1841 wideViewportTextView.setVisibility(View.GONE);
1844 case DomainsDatabaseHelper.DISABLED:
1845 // Set the icon according to the theme.
1847 wideViewportImageView.setImageDrawable(resources.getDrawable(R.drawable.wide_viewport_disabled_dark));
1849 wideViewportImageView.setImageDrawable(resources.getDrawable(R.drawable.wide_viewport_disabled_light));
1852 // Hid ethe wide viewport text view.
1853 wideViewportTextView.setVisibility(View.GONE);
1859 public void onNothingSelected(AdapterView<?> parent) {
1864 // Set the display webpage images spinner listener.
1865 displayWebpageImagesSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1867 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1868 // Update the icon and the visibility of the display images text view.
1870 case DomainsDatabaseHelper.SYSTEM_DEFAULT:
1871 if (defaultDisplayWebpageImages) { // Display webpage images is enabled by default.
1872 // Set the icon according to the theme.
1874 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_dark));
1876 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_light));
1878 } else { // Display webpage images is disabled by default.
1879 // Set the icon according to the theme.
1881 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_dark));
1883 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_light));
1887 // Show the display images text view.
1888 displayImagesTextView.setVisibility(View.VISIBLE);
1891 case DomainsDatabaseHelper.ENABLED:
1892 // Set the icon according to the theme.
1894 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_dark));
1896 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_light));
1899 // Hide the display images text view.
1900 displayImagesTextView.setVisibility(View.GONE);
1903 case DomainsDatabaseHelper.DISABLED:
1904 // Set the icon according to the theme.
1906 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_dark));
1908 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_light));
1911 // Hide the display images text view.
1912 displayImagesTextView.setVisibility(View.GONE);
1918 public void onNothingSelected(AdapterView<?> parent) {
1923 // Set the pinned SSL certificate switch listener.
1924 pinnedSslCertificateSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1926 if (isChecked) { // SSL certificate pinning is enabled.
1927 // Set the icon according to the theme.
1929 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_dark));
1931 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_light));
1934 // Update the visibility of the saved SSL certificate.
1935 if (savedSslIssuedToCNameString == null) {
1936 savedSslCardView.setVisibility(View.GONE);
1938 savedSslCardView.setVisibility(View.VISIBLE);
1941 // Update the visibility of the current website SSL certificate.
1942 if (DomainsActivity.sslIssuedToCName == null) {
1943 // Hide the SSL certificate.
1944 currentSslCardView.setVisibility(View.GONE);
1946 // Show the instruction.
1947 noCurrentWebsiteCertificateTextView.setVisibility(View.VISIBLE);
1949 // Show the SSL certificate.
1950 currentSslCardView.setVisibility(View.VISIBLE);
1952 // Hide the instruction.
1953 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
1956 // Set the status of the radio buttons.
1957 if (savedSslCardView.getVisibility() == View.VISIBLE) { // The saved SSL certificate is displayed.
1958 // Check the saved SSL certificate radio button.
1959 savedSslCertificateRadioButton.setChecked(true);
1961 // Uncheck the current website SSL certificate radio button.
1962 currentWebsiteCertificateRadioButton.setChecked(false);
1964 // Set the background of the saved SSL certificate linear layout to be transparent.
1965 savedSslCertificateLinearLayout.setBackgroundResource(R.color.transparent);
1967 // Darken the background of the current website SSL certificate linear layout according to the theme.
1969 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1971 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1974 // Scroll to the current website SSL certificate card.
1975 savedSslCardView.getParent().requestChildFocus(savedSslCardView, savedSslCardView);
1976 } else if (currentSslCardView.getVisibility() == View.VISIBLE) { // The saved SSL certificate is hidden but the current website SSL certificate is visible.
1977 // Check the current website SSL certificate radio button.
1978 currentWebsiteCertificateRadioButton.setChecked(true);
1980 // Uncheck the saved SSL certificate radio button.
1981 savedSslCertificateRadioButton.setChecked(false);
1983 // Set the background of the current website SSL certificate linear layout to be transparent.
1984 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.transparent);
1986 // Darken the background of the saved SSL certificate linear layout according to the theme.
1988 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1990 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1993 // Scroll to the current website SSL certificate card.
1994 currentSslCardView.getParent().requestChildFocus(currentSslCardView, currentSslCardView);
1995 } else { // Neither SSL certificate is visible.
1996 // Uncheck both radio buttons.
1997 savedSslCertificateRadioButton.setChecked(false);
1998 currentWebsiteCertificateRadioButton.setChecked(false);
2000 // Scroll to the current website SSL certificate card.
2001 noCurrentWebsiteCertificateTextView.getParent().requestChildFocus(noCurrentWebsiteCertificateTextView, noCurrentWebsiteCertificateTextView);
2003 } else { // SSL certificate pinning is disabled.
2004 // Set the icon according to the theme.
2006 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_dark));
2008 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_light));
2011 // Hide the SSl certificates and instructions.
2012 savedSslCardView.setVisibility(View.GONE);
2013 currentSslCardView.setVisibility(View.GONE);
2014 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
2016 // Uncheck the radio buttons.
2017 savedSslCertificateRadioButton.setChecked(false);
2018 currentWebsiteCertificateRadioButton.setChecked(false);
2022 savedSslCardView.setOnClickListener((View view) -> {
2023 // Check the saved SSL certificate radio button.
2024 savedSslCertificateRadioButton.setChecked(true);
2026 // Uncheck the current website SSL certificate radio button.
2027 currentWebsiteCertificateRadioButton.setChecked(false);
2029 // Set the background of the saved SSL certificate linear layout to be transparent.
2030 savedSslCertificateLinearLayout.setBackgroundResource(R.color.transparent);
2032 // Darken the background of the current website SSL certificate linear layout according to the theme.
2034 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2036 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2040 savedSslCertificateRadioButton.setOnClickListener((View view) -> {
2041 // Check the saved SSL certificate radio button.
2042 savedSslCertificateRadioButton.setChecked(true);
2044 // Uncheck the current website SSL certificate radio button.
2045 currentWebsiteCertificateRadioButton.setChecked(false);
2047 // Set the background of the saved SSL certificate linear layout to be transparent.
2048 savedSslCertificateLinearLayout.setBackgroundResource(R.color.transparent);
2050 // Darken the background of the current website SSL certificate linear layout according to the theme.
2052 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2054 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2058 currentSslCardView.setOnClickListener((View view) -> {
2059 // Check the current website SSL certificate radio button.
2060 currentWebsiteCertificateRadioButton.setChecked(true);
2062 // Uncheck the saved SSL certificate radio button.
2063 savedSslCertificateRadioButton.setChecked(false);
2065 // Set the background of the current website SSL certificate linear layout to be transparent.
2066 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.transparent);
2068 // Darken the background of the saved SSL certificate linear layout according to the theme.
2070 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2072 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2076 currentWebsiteCertificateRadioButton.setOnClickListener((View view) -> {
2077 // Check the current website SSL certificate radio button.
2078 currentWebsiteCertificateRadioButton.setChecked(true);
2080 // Uncheck the saved SSL certificate radio button.
2081 savedSslCertificateRadioButton.setChecked(false);
2083 // Set the background of the current website SSL certificate linear layout to be transparent.
2084 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.transparent);
2086 // Darken the background of the saved SSL certificate linear layout according to the theme.
2088 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2090 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2094 // Set the pinned IP addresses switch listener.
2095 pinnedIpAddressesSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
2097 if (isChecked) { // IP addresses pinning is enabled.
2098 // Set the icon according to the theme.
2100 pinnedIpAddressesImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_dark));
2102 pinnedIpAddressesImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_light));
2105 // Update the visibility of the saved IP addresses card view.
2106 if (savedIpAddresses == null) { // There are no saved IP addresses.
2107 savedIpAddressesCardView.setVisibility(View.GONE);
2108 } else { // There are saved IP addresses.
2109 savedIpAddressesCardView.setVisibility(View.VISIBLE);
2112 // Show the current IP addresses card view.
2113 currentIpAddressesCardView.setVisibility(View.VISIBLE);
2115 // Set the status of the radio buttons.
2116 if (savedIpAddressesCardView.getVisibility() == View.VISIBLE) { // The saved IP addresses are visible.
2117 // Check the saved IP addresses radio button.
2118 savedIpAddressesRadioButton.setChecked(true);
2120 // Uncheck the current IP addresses radio button.
2121 currentIpAddressesRadioButton.setChecked(false);
2123 // Set the background of the saved IP addresses linear layout to be transparent.
2124 savedSslCertificateLinearLayout.setBackgroundResource(R.color.transparent);
2126 // Darken the background of the current IP addresses linear layout according to the theme.
2128 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2130 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2132 } else { // The saved IP addresses are not visible.
2133 // Check the current IP addresses radio button.
2134 currentIpAddressesRadioButton.setChecked(true);
2136 // Uncheck the saved IP addresses radio button.
2137 savedIpAddressesRadioButton.setChecked(false);
2139 // Set the background of the current IP addresses linear layout to be transparent.
2140 currentIpAddressesLinearLayout.setBackgroundResource(R.color.transparent);
2142 // Darken the background of the saved IP addresses linear layout according to the theme.
2144 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2146 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2150 // Scroll to the bottom of the card views.
2151 currentIpAddressesCardView.getParent().requestChildFocus(currentIpAddressesCardView, currentIpAddressesCardView);
2152 } else { // IP addresses pinning is disabled.
2153 // Set the icon according to the theme.
2155 pinnedIpAddressesImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_dark));
2157 pinnedIpAddressesImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_light));
2160 // Hide the IP addresses card views.
2161 savedIpAddressesCardView.setVisibility(View.GONE);
2162 currentIpAddressesCardView.setVisibility(View.GONE);
2164 // Uncheck the radio buttons.
2165 savedIpAddressesRadioButton.setChecked(false);
2166 currentIpAddressesRadioButton.setChecked(false);
2170 savedIpAddressesCardView.setOnClickListener((View view) -> {
2171 // Check the saved IP addresses radio button.
2172 savedIpAddressesRadioButton.setChecked(true);
2174 // Uncheck the current website IP addresses radio button.
2175 currentIpAddressesRadioButton.setChecked(false);
2177 // Set the background of the saved IP addresses linear layout to be transparent.
2178 savedIpAddressesLinearLayout.setBackgroundResource(R.color.transparent);
2180 // Darken the background of the current IP addresses linear layout according to the theme.
2182 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2184 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2188 savedIpAddressesRadioButton.setOnClickListener((View view) -> {
2189 // Check the saved IP addresses radio button.
2190 savedIpAddressesRadioButton.setChecked(true);
2192 // Uncheck the current website IP addresses radio button.
2193 currentIpAddressesRadioButton.setChecked(false);
2195 // Set the background of the saved IP addresses linear layout to be transparent.
2196 savedIpAddressesLinearLayout.setBackgroundResource(R.color.transparent);
2198 // Darken the background of the current IP addresses linear layout according to the theme.
2200 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2202 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2206 currentIpAddressesCardView.setOnClickListener((View view) -> {
2207 // Check the current IP addresses radio button.
2208 currentIpAddressesRadioButton.setChecked(true);
2210 // Uncheck the saved IP addresses radio button.
2211 savedIpAddressesRadioButton.setChecked(false);
2213 // Set the background of the current IP addresses linear layout to be transparent.
2214 currentIpAddressesLinearLayout.setBackgroundResource(R.color.transparent);
2216 // Darken the background of the saved IP addresses linear layout according to the theme.
2218 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2220 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2224 currentIpAddressesRadioButton.setOnClickListener((View view) -> {
2225 // Check the current IP addresses radio button.
2226 currentIpAddressesRadioButton.setChecked(true);
2228 // Uncheck the saved IP addresses radio button.
2229 savedIpAddressesRadioButton.setChecked(false);
2231 // Set the background of the current IP addresses linear layout to be transparent.
2232 currentIpAddressesLinearLayout.setBackgroundResource(R.color.transparent);
2234 // Darken the background of the saved IP addresses linear layout according to the theme.
2236 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2238 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2242 return domainSettingsView;
2245 private boolean checkDomainNameAgainstCertificate(String domainName, String certificateCommonName) {
2246 // Initialize `domainNamesMatch`.
2247 boolean domainNamesMatch = false;
2249 // Check various wildcard permutations if `domainName` and `certificateCommonName` are not empty.
2250 // `noinspection ConstantCondition` removes Android Studio's incorrect lint warning that `domainName` can never be `null`.
2251 if ((domainName != null) && (certificateCommonName != null)) {
2252 // Check if the domains match.
2253 if (domainName.equals(certificateCommonName)) {
2254 domainNamesMatch = true;
2257 // If `domainName` starts with a wildcard, check the base domain against all the subdomains of `certificateCommonName`.
2258 if (!domainNamesMatch && domainName.startsWith("*.") && (domainName.length() > 2)) {
2259 // Remove the initial `*.`.
2260 String baseDomainName = domainName.substring(2);
2262 // Setup a copy of `certificateCommonName` to test subdomains.
2263 String certificateCommonNameSubdomain = certificateCommonName;
2265 // Check all the subdomains in `certificateCommonNameSubdomain` against `baseDomainName`.
2266 while (!domainNamesMatch && certificateCommonNameSubdomain.contains(".")) { // Stop checking if we know that `domainNamesMatch` is `true` or if we run out of `.`.
2267 // Test the `certificateCommonNameSubdomain` against `baseDomainName`.
2268 if (certificateCommonNameSubdomain.equals(baseDomainName)) {
2269 domainNamesMatch = true;
2272 // Strip out the lowest subdomain of `certificateCommonNameSubdomain`.
2274 certificateCommonNameSubdomain = certificateCommonNameSubdomain.substring(certificateCommonNameSubdomain.indexOf(".") + 1);
2275 } catch (IndexOutOfBoundsException e) { // `certificateCommonNameSubdomain` ends with `.`.
2276 certificateCommonNameSubdomain = "";
2281 // If `certificateCommonName` starts with a wildcard, check the base common name against all the subdomains of `domainName`.
2282 if (!domainNamesMatch && certificateCommonName.startsWith("*.") && (certificateCommonName.length() > 2)) {
2283 // Remove the initial `*.`.
2284 String baseCertificateCommonName = certificateCommonName.substring(2);
2286 // Setup a copy of `domainName` to test subdomains.
2287 String domainNameSubdomain = domainName;
2289 // Check all the subdomains in `domainNameSubdomain` against `baseCertificateCommonName`.
2290 while (!domainNamesMatch && domainNameSubdomain.contains(".") && (domainNameSubdomain.length() > 2)) {
2291 // Test the `domainNameSubdomain` against `baseCertificateCommonName`.
2292 if (domainNameSubdomain.equals(baseCertificateCommonName)) {
2293 domainNamesMatch = true;
2296 // Strip out the lowest subdomain of `domainNameSubdomain`.
2298 domainNameSubdomain = domainNameSubdomain.substring(domainNameSubdomain.indexOf(".") + 1);
2299 } catch (IndexOutOfBoundsException e) { // `domainNameSubdomain` ends with `.`.
2300 domainNameSubdomain = "";
2305 // If both names start with a wildcard, check if the root of one contains the root of the other.
2306 if (!domainNamesMatch && domainName.startsWith("*.") && (domainName.length() > 2) && certificateCommonName.startsWith("*.") && (certificateCommonName.length() > 2)) {
2307 // Remove the wildcards.
2308 String rootDomainName = domainName.substring(2);
2309 String rootCertificateCommonName = certificateCommonName.substring(2);
2311 // Check if one name ends with the contents of the other. If so, there will be overlap in the their wildcard subdomains.
2312 if (rootDomainName.endsWith(rootCertificateCommonName) || rootCertificateCommonName.endsWith(rootDomainName)) {
2313 domainNamesMatch = true;
2318 return domainNamesMatch;