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 ImageView javaScriptImageView = domainSettingsView.findViewById(R.id.javascript_imageview);
111 Switch javaScriptSwitch = domainSettingsView.findViewById(R.id.javascript_switch);
112 ImageView firstPartyCookiesImageView = domainSettingsView.findViewById(R.id.first_party_cookies_imageview);
113 Switch firstPartyCookiesSwitch = domainSettingsView.findViewById(R.id.first_party_cookies_switch);
114 LinearLayout thirdPartyCookiesLinearLayout = domainSettingsView.findViewById(R.id.third_party_cookies_linearlayout);
115 ImageView thirdPartyCookiesImageView = domainSettingsView.findViewById(R.id.third_party_cookies_imageview);
116 Switch thirdPartyCookiesSwitch = domainSettingsView.findViewById(R.id.third_party_cookies_switch);
117 ImageView domStorageImageView = domainSettingsView.findViewById(R.id.dom_storage_imageview);
118 Switch domStorageSwitch = domainSettingsView.findViewById(R.id.dom_storage_switch);
119 ImageView formDataImageView = domainSettingsView.findViewById(R.id.form_data_imageview); // The form data views can be remove once the minimum API >= 26.
120 Switch formDataSwitch = domainSettingsView.findViewById(R.id.form_data_switch); // The form data views can be remove once the minimum API >= 26.
121 ImageView easyListImageView = domainSettingsView.findViewById(R.id.easylist_imageview);
122 Switch easyListSwitch = domainSettingsView.findViewById(R.id.easylist_switch);
123 ImageView easyPrivacyImageView = domainSettingsView.findViewById(R.id.easyprivacy_imageview);
124 Switch easyPrivacySwitch = domainSettingsView.findViewById(R.id.easyprivacy_switch);
125 ImageView fanboysAnnoyanceListImageView = domainSettingsView.findViewById(R.id.fanboys_annoyance_list_imageview);
126 Switch fanboysAnnoyanceListSwitch = domainSettingsView.findViewById(R.id.fanboys_annoyance_list_switch);
127 ImageView fanboysSocialBlockingListImageView = domainSettingsView.findViewById(R.id.fanboys_social_blocking_list_imageview);
128 Switch fanboysSocialBlockingListSwitch = domainSettingsView.findViewById(R.id.fanboys_social_blocking_list_switch);
129 ImageView ultraListImageView = domainSettingsView.findViewById(R.id.ultralist_imageview);
130 Switch ultraListSwitch = domainSettingsView.findViewById(R.id.ultralist_switch);
131 ImageView ultraPrivacyImageView = domainSettingsView.findViewById(R.id.ultraprivacy_imageview);
132 Switch ultraPrivacySwitch = domainSettingsView.findViewById(R.id.ultraprivacy_switch);
133 ImageView blockAllThirdPartyRequestsImageView = domainSettingsView.findViewById(R.id.block_all_third_party_requests_imageview);
134 Switch blockAllThirdPartyRequestsSwitch = domainSettingsView.findViewById(R.id.block_all_third_party_requests_switch);
135 Spinner userAgentSpinner = domainSettingsView.findViewById(R.id.user_agent_spinner);
136 TextView userAgentTextView = domainSettingsView.findViewById(R.id.user_agent_textview);
137 EditText customUserAgentEditText = domainSettingsView.findViewById(R.id.custom_user_agent_edittext);
138 Spinner fontSizeSpinner = domainSettingsView.findViewById(R.id.font_size_spinner);
139 TextView fontSizeTextView = domainSettingsView.findViewById(R.id.font_size_textview);
140 ImageView swipeToRefreshImageView = domainSettingsView.findViewById(R.id.swipe_to_refresh_imageview);
141 Spinner swipeToRefreshSpinner = domainSettingsView.findViewById(R.id.swipe_to_refresh_spinner);
142 TextView swipeToRefreshTextView = domainSettingsView.findViewById(R.id.swipe_to_refresh_textview);
143 ImageView nightModeImageView = domainSettingsView.findViewById(R.id.night_mode_imageview);
144 Spinner nightModeSpinner = domainSettingsView.findViewById(R.id.night_mode_spinner);
145 TextView nightModeTextView = domainSettingsView.findViewById(R.id.night_mode_textview);
146 ImageView wideViewportImageView = domainSettingsView.findViewById(R.id.wide_viewport_imageview);
147 Spinner wideViewportSpinner = domainSettingsView.findViewById(R.id.wide_viewport_spinner);
148 TextView wideViewportTextView = domainSettingsView.findViewById(R.id.wide_viewport_textview);
149 ImageView displayWebpageImagesImageView = domainSettingsView.findViewById(R.id.display_webpage_images_imageview);
150 Spinner displayWebpageImagesSpinner = domainSettingsView.findViewById(R.id.display_webpage_images_spinner);
151 TextView displayImagesTextView = domainSettingsView.findViewById(R.id.display_webpage_images_textview);
152 ImageView pinnedSslCertificateImageView = domainSettingsView.findViewById(R.id.pinned_ssl_certificate_imageview);
153 Switch pinnedSslCertificateSwitch = domainSettingsView.findViewById(R.id.pinned_ssl_certificate_switch);
154 CardView savedSslCardView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_cardview);
155 LinearLayout savedSslCertificateLinearLayout = domainSettingsView.findViewById(R.id.saved_ssl_certificate_linearlayout);
156 RadioButton savedSslCertificateRadioButton = domainSettingsView.findViewById(R.id.saved_ssl_certificate_radiobutton);
157 TextView savedSslIssuedToCNameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_to_cname);
158 TextView savedSslIssuedToONameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_to_oname);
159 TextView savedSslIssuedToUNameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_to_uname);
160 TextView savedSslIssuedByCNameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_by_cname);
161 TextView savedSslIssuedByONameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_by_oname);
162 TextView savedSslIssuedByUNameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_by_uname);
163 TextView savedSslStartDateTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_start_date);
164 TextView savedSslEndDateTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_end_date);
165 CardView currentSslCardView = domainSettingsView.findViewById(R.id.current_website_certificate_cardview);
166 LinearLayout currentWebsiteCertificateLinearLayout = domainSettingsView.findViewById(R.id.current_website_certificate_linearlayout);
167 RadioButton currentWebsiteCertificateRadioButton = domainSettingsView.findViewById(R.id.current_website_certificate_radiobutton);
168 TextView currentSslIssuedToCNameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_to_cname);
169 TextView currentSslIssuedToONameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_to_oname);
170 TextView currentSslIssuedToUNameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_to_uname);
171 TextView currentSslIssuedByCNameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_by_cname);
172 TextView currentSslIssuedByONameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_by_oname);
173 TextView currentSslIssuedByUNameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_by_uname);
174 TextView currentSslStartDateTextView = domainSettingsView.findViewById(R.id.current_website_certificate_start_date);
175 TextView currentSslEndDateTextView = domainSettingsView.findViewById(R.id.current_website_certificate_end_date);
176 TextView noCurrentWebsiteCertificateTextView = domainSettingsView.findViewById(R.id.no_current_website_certificate);
177 ImageView pinnedIpAddressesImageView = domainSettingsView.findViewById(R.id.pinned_ip_addresses_imageview);
178 Switch pinnedIpAddressesSwitch = domainSettingsView.findViewById(R.id.pinned_ip_addresses_switch);
179 CardView savedIpAddressesCardView = domainSettingsView.findViewById(R.id.saved_ip_addresses_cardview);
180 LinearLayout savedIpAddressesLinearLayout = domainSettingsView.findViewById(R.id.saved_ip_addresses_linearlayout);
181 RadioButton savedIpAddressesRadioButton = domainSettingsView.findViewById(R.id.saved_ip_addresses_radiobutton);
182 TextView savedIpAddressesTextView = domainSettingsView.findViewById(R.id.saved_ip_addresses_textview);
183 CardView currentIpAddressesCardView = domainSettingsView.findViewById(R.id.current_ip_addresses_cardview);
184 LinearLayout currentIpAddressesLinearLayout = domainSettingsView.findViewById(R.id.current_ip_addresses_linearlayout);
185 RadioButton currentIpAddressesRadioButton = domainSettingsView.findViewById(R.id.current_ip_addresses_radiobutton);
186 TextView currentIpAddressesTextView = domainSettingsView.findViewById(R.id.current_ip_addresses_textview);
188 // Setup the pinned labels.
189 String cNameLabel = getString(R.string.common_name) + " ";
190 String oNameLabel = getString(R.string.organization) + " ";
191 String uNameLabel = getString(R.string.organizational_unit) + " ";
192 String startDateLabel = getString(R.string.start_date) + " ";
193 String endDateLabel = getString(R.string.end_date) + " ";
195 // Initialize the database handler. The `0` specifies the database version, but that is ignored and set instead using a constant in `DomainsDatabaseHelper`.
196 DomainsDatabaseHelper domainsDatabaseHelper = new DomainsDatabaseHelper(context, null, null, 0);
198 // Get the database cursor for this ID and move it to the first row.
199 Cursor domainCursor = domainsDatabaseHelper.getCursorForId(databaseId);
200 domainCursor.moveToFirst();
202 // Save the cursor entries as variables.
203 String domainNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.DOMAIN_NAME));
204 int javaScriptInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_JAVASCRIPT));
205 int firstPartyCookiesInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FIRST_PARTY_COOKIES));
206 int thirdPartyCookiesInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_THIRD_PARTY_COOKIES));
207 int domStorageInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_DOM_STORAGE));
208 int formDataInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FORM_DATA)); // Form data can be remove once the minimum API >= 26.
209 int easyListInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_EASYLIST));
210 int easyPrivacyInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_EASYPRIVACY));
211 int fanboysAnnoyanceListInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FANBOYS_ANNOYANCE_LIST));
212 int fanboysSocialBlockingListInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FANBOYS_SOCIAL_BLOCKING_LIST));
213 int ultraListInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ULTRALIST));
214 int ultraPrivacyInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_ULTRAPRIVACY));
215 int blockAllThirdPartyRequestsInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.BLOCK_ALL_THIRD_PARTY_REQUESTS));
216 String currentUserAgentName = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.USER_AGENT));
217 int fontSizeInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.FONT_SIZE));
218 int swipeToRefreshInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.SWIPE_TO_REFRESH));
219 int nightModeInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.NIGHT_MODE));
220 int wideViewportInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.WIDE_VIEWPORT));
221 int displayImagesInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.DISPLAY_IMAGES));
222 int pinnedSslCertificateInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.PINNED_SSL_CERTIFICATE));
223 String savedSslIssuedToCNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_TO_COMMON_NAME));
224 String savedSslIssuedToONameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_TO_ORGANIZATION));
225 String savedSslIssuedToUNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_TO_ORGANIZATIONAL_UNIT));
226 String savedSslIssuedByCNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_BY_COMMON_NAME));
227 String savedSslIssuedByONameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_BY_ORGANIZATION));
228 String savedSslIssuedByUNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_BY_ORGANIZATIONAL_UNIT));
229 int pinnedIpAddressesInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.PINNED_IP_ADDRESSES));
230 String savedIpAddresses = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.IP_ADDRESSES));
232 // Initialize the saved SSL certificate date variables.
233 Date savedSslStartDate = null;
234 Date savedSslEndDate = null;
236 // Only get the saved SSL certificate dates from the cursor if they are not set to `0`.
237 if (domainCursor.getLong(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_START_DATE)) != 0) {
238 savedSslStartDate = new Date(domainCursor.getLong(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_START_DATE)));
241 if (domainCursor.getLong(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_END_DATE)) != 0) {
242 savedSslEndDate = new Date(domainCursor.getLong(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_END_DATE)));
245 // Create array adapters for the spinners.
246 ArrayAdapter<CharSequence> translatedUserAgentArrayAdapter = ArrayAdapter.createFromResource(context, R.array.translated_domain_settings_user_agent_names, R.layout.spinner_item);
247 ArrayAdapter<CharSequence> fontSizeArrayAdapter = ArrayAdapter.createFromResource(context, R.array.domain_settings_font_size_entries, R.layout.spinner_item);
248 ArrayAdapter<CharSequence> fontSizeEntryValuesArrayAdapter = ArrayAdapter.createFromResource(context, R.array.domain_settings_font_size_entry_values, R.layout.spinner_item);
249 ArrayAdapter<CharSequence> swipeToRefreshArrayAdapter = ArrayAdapter.createFromResource(context, R.array.swipe_to_refresh_array, R.layout.spinner_item);
250 ArrayAdapter<CharSequence> nightModeArrayAdapter = ArrayAdapter.createFromResource(context, R.array.night_mode_array, R.layout.spinner_item);
251 ArrayAdapter<CharSequence> wideViewportArrayAdapter = ArrayAdapter.createFromResource(context, R.array.wide_viewport_array, R.layout.spinner_item);
252 ArrayAdapter<CharSequence> displayImagesArrayAdapter = ArrayAdapter.createFromResource(context, R.array.display_webpage_images_array, R.layout.spinner_item);
254 // Set the drop down view resource on the spinners.
255 translatedUserAgentArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items);
256 fontSizeArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items);
257 swipeToRefreshArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items);
258 nightModeArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items);
259 wideViewportArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items);
260 displayImagesArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items);
262 // Set the array adapters for the spinners.
263 userAgentSpinner.setAdapter(translatedUserAgentArrayAdapter);
264 fontSizeSpinner.setAdapter(fontSizeArrayAdapter);
265 swipeToRefreshSpinner.setAdapter(swipeToRefreshArrayAdapter);
266 nightModeSpinner.setAdapter(nightModeArrayAdapter);
267 wideViewportSpinner.setAdapter(wideViewportArrayAdapter);
268 displayWebpageImagesSpinner.setAdapter(displayImagesArrayAdapter);
270 // Create a spannable string builder for each TextView that needs multiple colors of text.
271 SpannableStringBuilder savedSslIssuedToCNameStringBuilder = new SpannableStringBuilder(cNameLabel + savedSslIssuedToCNameString);
272 SpannableStringBuilder savedSslIssuedToONameStringBuilder = new SpannableStringBuilder(oNameLabel + savedSslIssuedToONameString);
273 SpannableStringBuilder savedSslIssuedToUNameStringBuilder = new SpannableStringBuilder(uNameLabel + savedSslIssuedToUNameString);
274 SpannableStringBuilder savedSslIssuedByCNameStringBuilder = new SpannableStringBuilder(cNameLabel + savedSslIssuedByCNameString);
275 SpannableStringBuilder savedSslIssuedByONameStringBuilder = new SpannableStringBuilder(oNameLabel + savedSslIssuedByONameString);
276 SpannableStringBuilder savedSslIssuedByUNameStringBuilder = new SpannableStringBuilder(uNameLabel + savedSslIssuedByUNameString);
278 // Initialize the spannable string builders for the saved SSL certificate dates.
279 SpannableStringBuilder savedSslStartDateStringBuilder;
280 SpannableStringBuilder savedSslEndDateStringBuilder;
282 // Leave the SSL certificate dates empty if they are `null`.
283 if (savedSslStartDate == null) {
284 savedSslStartDateStringBuilder = new SpannableStringBuilder(startDateLabel);
286 savedSslStartDateStringBuilder = new SpannableStringBuilder(startDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(savedSslStartDate));
289 if (savedSslEndDate == null) {
290 savedSslEndDateStringBuilder = new SpannableStringBuilder(endDateLabel);
292 savedSslEndDateStringBuilder = new SpannableStringBuilder(endDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(savedSslEndDate));
295 // Create a red foreground color span. The deprecated `resources.getColor` must be used until the minimum API >= 23.
296 final ForegroundColorSpan redColorSpan = new ForegroundColorSpan(resources.getColor(R.color.red_a700));
298 // Create a blue foreground color span.
299 final ForegroundColorSpan blueColorSpan;
301 // Set the blue color span according to the theme. The deprecated `resources.getColor` must be used until the minimum API >= 23.
303 blueColorSpan = new ForegroundColorSpan(resources.getColor(R.color.blue_400));
305 blueColorSpan = new ForegroundColorSpan(resources.getColor(R.color.blue_700));
308 // Set the domain name from the the database cursor.
309 domainNameEditText.setText(domainNameString);
311 // Update the certificates' `Common Name` color when the domain name text changes.
312 domainNameEditText.addTextChangedListener(new TextWatcher() {
314 public void beforeTextChanged(CharSequence s, int start, int count, int after) {
319 public void onTextChanged(CharSequence s, int start, int before, int count) {
324 public void afterTextChanged(Editable s) {
325 // Get the new domain name.
326 String newDomainName = domainNameEditText.getText().toString();
328 // Check the saved SSL certificate against the new domain name.
329 boolean savedSslMatchesNewDomainName = checkDomainNameAgainstCertificate(newDomainName, savedSslIssuedToCNameString);
331 // Create a `SpannableStringBuilder` for the saved certificate `Common Name`.
332 SpannableStringBuilder savedSslCNameStringBuilder = new SpannableStringBuilder(cNameLabel + savedSslIssuedToCNameString);
334 // Format the saved certificate `Common Name` color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
335 if (savedSslMatchesNewDomainName) {
336 savedSslCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), savedSslCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
338 savedSslCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), savedSslCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
341 // Update the saved SSL issued to CName text view.
342 savedSslIssuedToCNameTextView.setText(savedSslCNameStringBuilder);
344 // Update the current website certificate if it exists.
345 if (DomainsActivity.sslIssuedToCName != null) {
346 // Check the current website certificate against the new domain name.
347 boolean currentSslMatchesNewDomainName = checkDomainNameAgainstCertificate(newDomainName, DomainsActivity.sslIssuedToCName);
349 // Create a `SpannableStringBuilder` for the current website certificate `Common Name`.
350 SpannableStringBuilder currentSslCNameStringBuilder = new SpannableStringBuilder(cNameLabel + DomainsActivity.sslIssuedToCName);
352 // Format the current certificate `Common Name` color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
353 if (currentSslMatchesNewDomainName) {
354 currentSslCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), currentSslCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
356 currentSslCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), currentSslCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
359 // Update the current SSL issued to CName text view.
360 currentSslIssuedToCNameTextView.setText(currentSslCNameStringBuilder);
365 // Create a boolean to track if night mode is enabled.
366 boolean nightModeEnabled = (nightModeInt == DomainsDatabaseHelper.ENABLED) || ((nightModeInt == DomainsDatabaseHelper.SYSTEM_DEFAULT) && defaultNightMode);
368 // Disable the JavaScript switch if night mode is enabled.
369 if (nightModeEnabled) {
370 javaScriptSwitch.setEnabled(false);
372 javaScriptSwitch.setEnabled(true);
375 // Set the JavaScript icon.
376 if ((javaScriptInt == 1) || nightModeEnabled) {
377 javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.javascript_enabled));
379 javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.privacy_mode));
382 // Set the JavaScript switch status.
383 if (javaScriptInt == 1) { // JavaScript is enabled.
384 javaScriptSwitch.setChecked(true);
385 } else { // JavaScript is disabled.
386 javaScriptSwitch.setChecked(false);
389 // 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.
390 if (firstPartyCookiesInt == 1) { // First-party cookies are enabled.
391 firstPartyCookiesSwitch.setChecked(true);
392 firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_enabled));
393 } else { // First-party cookies are disabled.
394 firstPartyCookiesSwitch.setChecked(false);
396 // Set the icon according to the theme.
398 firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_dark));
400 firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_light));
404 // Only display third-party cookies if SDK_INT >= 21.
405 if (Build.VERSION.SDK_INT >= 21) { // Third-party cookies can be configured for API >= 21.
406 // Only enable third-party-cookies if first-party cookies are enabled.
407 if (firstPartyCookiesInt == 1) { // First-party cookies are enabled.
408 // 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.
409 if (thirdPartyCookiesInt == 1) { // Both first-party and third-party cookies are enabled.
410 thirdPartyCookiesSwitch.setChecked(true);
411 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_warning));
412 } else { // First party cookies are enabled but third-party cookies are disabled.
413 thirdPartyCookiesSwitch.setChecked(false);
415 // Set the icon according to the theme.
417 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_dark));
419 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_light));
422 } else { // First-party cookies are disabled.
423 // Set the status of third-party cookies.
424 if (thirdPartyCookiesInt == 1) {
425 thirdPartyCookiesSwitch.setChecked(true);
427 thirdPartyCookiesSwitch.setChecked(false);
430 // Disable the third-party cookies switch.
431 thirdPartyCookiesSwitch.setEnabled(false);
433 // Set the icon according to the theme.
435 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_ghosted_dark));
437 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_ghosted_light));
440 } else { // Third-party cookies cannot be configured for API <= 21.
441 // Hide the LinearLayout for third-party cookies.
442 thirdPartyCookiesLinearLayout.setVisibility(View.GONE);
445 // Only enable DOM storage if JavaScript is enabled.
446 if ((javaScriptInt == 1) || nightModeEnabled) { // JavaScript is enabled.
447 // Enable the DOM storage `Switch`.
448 domStorageSwitch.setEnabled(true);
450 // Set the DOM storage status. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
451 if (domStorageInt == 1) { // Both JavaScript and DOM storage are enabled.
452 domStorageSwitch.setChecked(true);
453 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_enabled));
454 } else { // JavaScript is enabled but DOM storage is disabled.
455 // Set the DOM storage switch to off.
456 domStorageSwitch.setChecked(false);
458 // Set the icon according to the theme.
460 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_dark));
462 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_light));
465 } else { // JavaScript is disabled.
466 // Disable the DOM storage `Switch`.
467 domStorageSwitch.setEnabled(false);
469 // Set the checked status of DOM storage.
470 if (domStorageInt == 1) { // DOM storage is enabled but JavaScript is disabled.
471 domStorageSwitch.setChecked(true);
472 } else { // Both JavaScript and DOM storage are disabled.
473 domStorageSwitch.setChecked(false);
476 // Set the icon according to the theme.
478 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_dark));
480 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_light));
484 // 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.
485 if (Build.VERSION.SDK_INT >= 26) { // Form data no longer applies to newer versions of Android.
486 // Hide the form data switch.
487 formDataSwitch.setVisibility(View.GONE);
488 } else { // Form data should be displayed because this is an older version of Android.
489 if (formDataInt == 1) { // Form data is on.
490 formDataSwitch.setChecked(true);
491 formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_enabled));
492 } else { // Form data is off.
493 // Turn the form data switch to off.
494 formDataSwitch.setChecked(false);
496 // Set the icon according to the theme.
498 formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_disabled_dark));
500 formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_disabled_light));
505 // Set the EasyList status. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
506 if (easyListInt == 1) { // EasyList is on.
507 // Turn the switch on.
508 easyListSwitch.setChecked(true);
510 // Set the icon according to the theme.
512 easyListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_enabled_dark));
514 easyListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_enabled_light));
516 } else { // EasyList is off.
517 // Turn the switch off.
518 easyListSwitch.setChecked(false);
520 // Set the icon according to the theme.
522 easyListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_disabled_dark));
524 easyListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_disabled_light));
528 // Set the EasyPrivacy status. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
529 if (easyPrivacyInt == 1) { // EasyPrivacy is on.
530 // Turn the switch on.
531 easyPrivacySwitch.setChecked(true);
533 // Set the icon according to the theme.
535 easyPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_enabled_dark));
537 easyPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_enabled_light));
539 } else { // EasyPrivacy is off.
540 // Turn the switch off.
541 easyPrivacySwitch.setChecked(false);
543 // Set the icon according to the theme.
545 easyPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_disabled_dark));
547 easyPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_disabled_light));
551 // 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.
552 if (fanboysAnnoyanceListInt == 1) { // Fanboy's Annoyance List is on.
553 // Turn the switch on.
554 fanboysAnnoyanceListSwitch.setChecked(true);
556 // Set the icon according to the theme.
558 fanboysAnnoyanceListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_dark));
560 fanboysAnnoyanceListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_light));
562 } else { // Fanboy's Annoyance List is off.
563 // Turn the switch off.
564 fanboysAnnoyanceListSwitch.setChecked(false);
566 // Set the icon according to the theme.
568 fanboysAnnoyanceListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_dark));
570 fanboysAnnoyanceListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_light));
574 // Only enable Fanboy's Social Blocking List if Fanboy's Annoyance List is off.
575 if (fanboysAnnoyanceListInt == 0) { // Fanboy's Annoyance List is on.
576 // 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.
577 if (fanboysSocialBlockingListInt == 1) { // Fanboy's Social Blocking List is on.
578 // Enable the switch and turn it on.
579 fanboysSocialBlockingListSwitch.setEnabled(true);
580 fanboysSocialBlockingListSwitch.setChecked(true);
582 // Set the icon according to the theme.
584 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_dark));
586 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_light));
588 } else { // Fanboy's Social Blocking List is off.
589 // Enable the switch but turn it off.
590 fanboysSocialBlockingListSwitch.setEnabled(true);
591 fanboysSocialBlockingListSwitch.setChecked(false);
593 // Set the icon according to the theme.
595 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_dark));
597 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_light));
600 } else { // Fanboy's Annoyance List is on.
601 // 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.
602 if (fanboysSocialBlockingListInt == 1) { // Fanboy's Social Blocking List is on.
603 // Disable the switch but turn it on.
604 fanboysSocialBlockingListSwitch.setEnabled(false);
605 fanboysSocialBlockingListSwitch.setChecked(true);
606 } else { // Fanboy's Social Blocking List is off.
607 // Disable the switch and turn it off.
608 fanboysSocialBlockingListSwitch.setEnabled(false);
609 fanboysSocialBlockingListSwitch.setChecked(false);
612 // Set the icon according to the theme.
614 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_ghosted_dark));
616 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_ghosted_light));
620 // Set the UltraList status. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
621 if (ultraListInt == 1) { // UltraList is on.
622 // Turn the switch on.
623 ultraListSwitch.setChecked(true);
625 // Set the icon according to the theme.
627 ultraListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_enabled_dark));
629 ultraListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_enabled_light));
631 } else { // UltraList is off.
632 // Turn the switch off.
633 ultraListSwitch.setChecked(false);
635 // Set the icon according to the theme.
637 ultraListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_disabled_dark));
639 ultraListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_disabled_light));
643 // Set the UltraPrivacy status. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
644 if (ultraPrivacyInt == 1) { // UltraPrivacy is on.
645 // Turn the switch on.
646 ultraPrivacySwitch.setChecked(true);
648 // Set the icon according to the theme.
650 ultraPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_enabled_dark));
652 ultraPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_enabled_light));
654 } else { // EasyPrivacy is off.
655 // Turn the switch off.
656 ultraPrivacySwitch.setChecked(false);
658 // Set the icon according to the theme.
660 ultraPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_disabled_dark));
662 ultraPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_disabled_light));
666 // 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.
667 if (blockAllThirdPartyRequestsInt == 1) { // Blocking all third-party requests is on.
668 // Turn the switch on.
669 blockAllThirdPartyRequestsSwitch.setChecked(true);
671 // Set the icon according to the theme.
673 blockAllThirdPartyRequestsImageView.setImageDrawable(resources.getDrawable(R.drawable.block_all_third_party_requests_enabled_dark));
675 blockAllThirdPartyRequestsImageView.setImageDrawable(resources.getDrawable(R.drawable.block_all_third_party_requests_enabled_light));
677 } else { // Blocking all third-party requests is off.
678 // Turn the switch off.
679 blockAllThirdPartyRequestsSwitch.setChecked(false);
681 // Set the icon according to the theme.
683 blockAllThirdPartyRequestsImageView.setImageDrawable(resources.getDrawable(R.drawable.block_all_third_party_requests_disabled_dark));
685 blockAllThirdPartyRequestsImageView.setImageDrawable(resources.getDrawable(R.drawable.block_all_third_party_requests_disabled_light));
689 // Inflated a WebView to get the default user agent.
690 // `@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.
691 @SuppressLint("InflateParams") View bareWebViewLayout = inflater.inflate(R.layout.bare_webview, null, false);
692 WebView bareWebView = bareWebViewLayout.findViewById(R.id.bare_webview);
693 final String webViewDefaultUserAgentString = bareWebView.getSettings().getUserAgentString();
695 // Get a handle for the user agent array adapter. This array does not contain the `System default` entry.
696 ArrayAdapter<CharSequence> userAgentNamesArray = ArrayAdapter.createFromResource(context, R.array.user_agent_names, R.layout.spinner_item);
698 // Get the positions of the user agent and the default user agent.
699 int userAgentArrayPosition = userAgentNamesArray.getPosition(currentUserAgentName);
700 int defaultUserAgentArrayPosition = userAgentNamesArray.getPosition(defaultUserAgentName);
702 // Get a handle for the user agent data array. This array does not contain the `System default` entry.
703 String[] userAgentDataArray = resources.getStringArray(R.array.user_agent_data);
705 // Set the user agent text.
706 if (currentUserAgentName.equals(getString(R.string.system_default_user_agent))) { // Use the system default user agent.
707 // Set the user agent according to the system default.
708 switch (defaultUserAgentArrayPosition) {
709 case MainWebViewActivity.UNRECOGNIZED_USER_AGENT: // The default user agent name is not on the canonical list.
710 // This is probably because it was set in an older version of Privacy Browser before the switch to persistent user agent names.
711 userAgentTextView.setText(defaultUserAgentName);
714 case MainWebViewActivity.SETTINGS_WEBVIEW_DEFAULT_USER_AGENT:
715 // Display the `WebView` default user agent.
716 userAgentTextView.setText(webViewDefaultUserAgentString);
719 case MainWebViewActivity.SETTINGS_CUSTOM_USER_AGENT:
720 // Display the custom user agent.
721 userAgentTextView.setText(defaultCustomUserAgentString);
725 // Get the user agent string from the user agent data array.
726 userAgentTextView.setText(userAgentDataArray[defaultUserAgentArrayPosition]);
728 } else if (userAgentArrayPosition == MainWebViewActivity.UNRECOGNIZED_USER_AGENT) { // A custom user agent is stored in the current user agent name.
729 // Set the user agent spinner to `Custom user agent`.
730 userAgentSpinner.setSelection(MainWebViewActivity.DOMAINS_CUSTOM_USER_AGENT);
732 // Hide the user agent TextView.
733 userAgentTextView.setVisibility(View.GONE);
735 // Show the custom user agent EditText and set the current user agent name as the text.
736 customUserAgentEditText.setVisibility(View.VISIBLE);
737 customUserAgentEditText.setText(currentUserAgentName);
738 } else { // The user agent name contains one of the canonical user agents.
739 // 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.
740 userAgentSpinner.setSelection(userAgentArrayPosition + 1);
742 // Show the user agent TextView.
743 userAgentTextView.setVisibility(View.VISIBLE);
745 // Hide the custom user agent EditText.
746 customUserAgentEditText.setVisibility(View.GONE);
748 // Set the user agent text.
749 if (userAgentArrayPosition == MainWebViewActivity.DOMAINS_WEBVIEW_DEFAULT_USER_AGENT) { // The WebView default user agent is selected.
750 // Display the WebView default user agent.
751 userAgentTextView.setText(webViewDefaultUserAgentString);
752 } else { // A user agent besides the default is selected.
753 // 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.
754 userAgentTextView.setText(userAgentDataArray[userAgentArrayPosition + 1]);
758 // Open the user agent spinner when the text view is clicked.
759 userAgentTextView.setOnClickListener((View v) -> {
760 // Open the user agent spinner.
761 userAgentSpinner.performClick();
764 // Set the selected font size.
765 int fontSizeArrayPosition = fontSizeEntryValuesArrayAdapter.getPosition(String.valueOf(fontSizeInt));
766 fontSizeSpinner.setSelection(fontSizeArrayPosition);
768 // Set the default font size text.
769 int defaultFontSizeArrayPosition = fontSizeEntryValuesArrayAdapter.getPosition(defaultFontSizeString);
770 fontSizeTextView.setText(fontSizeArrayAdapter.getItem(defaultFontSizeArrayPosition));
772 // Set the display options for the font size TextView.
773 if (fontSizeArrayPosition == 0) { // System default font size is selected. Display `fontSizeTextView`.
774 fontSizeTextView.setVisibility(View.VISIBLE);
775 } else { // A custom font size is specified. Hide `fontSizeTextView`.
776 fontSizeTextView.setVisibility(View.GONE);
779 // Open the font size spinner when the TextView is clicked.
780 fontSizeTextView.setOnClickListener((View v) -> {
781 // Open the user agent spinner.
782 fontSizeSpinner.performClick();
785 // Display the swipe to refresh selection in the spinner.
786 swipeToRefreshSpinner.setSelection(swipeToRefreshInt);
788 // Set the swipe to refresh text.
789 if (defaultSwipeToRefresh) {
790 swipeToRefreshTextView.setText(swipeToRefreshArrayAdapter.getItem(DomainsDatabaseHelper.ENABLED));
792 swipeToRefreshTextView.setText(swipeToRefreshArrayAdapter.getItem(DomainsDatabaseHelper.DISABLED));
795 // 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.
796 switch (swipeToRefreshInt) {
797 case DomainsDatabaseHelper.SYSTEM_DEFAULT:
798 if (defaultSwipeToRefresh) { // Swipe to refresh is enabled by default.
799 // Set the icon according to the theme.
801 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_enabled_dark));
803 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_enabled_light));
805 } else { // Swipe to refresh is disabled by default
806 // Set the icon according to the theme.
808 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_disabled_dark));
810 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_disabled_light));
814 // Show the swipe to refresh TextView.
815 swipeToRefreshTextView.setVisibility(View.VISIBLE);
818 case DomainsDatabaseHelper.ENABLED:
819 // Set the icon according to the theme.
821 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_enabled_dark));
823 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_enabled_light));
826 // Hide the swipe to refresh TextView.`
827 swipeToRefreshTextView.setVisibility(View.GONE);
830 case DomainsDatabaseHelper.DISABLED:
831 // Set the icon according to the theme.
833 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_disabled_dark));
835 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_disabled_light));
838 // Hide the swipe to refresh TextView.
839 swipeToRefreshTextView.setVisibility(View.GONE);
842 // Open the swipe to refresh spinner when the TextView is clicked.
843 swipeToRefreshTextView.setOnClickListener((View v) -> {
844 // Open the swipe to refresh spinner.
845 swipeToRefreshSpinner.performClick();
848 // Display the night mode in the spinner.
849 nightModeSpinner.setSelection(nightModeInt);
851 // Set the default night mode text.
852 if (defaultNightMode) {
853 nightModeTextView.setText(nightModeArrayAdapter.getItem(DomainsDatabaseHelper.ENABLED));
855 nightModeTextView.setText(nightModeArrayAdapter.getItem(DomainsDatabaseHelper.DISABLED));
858 // 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.
859 switch (nightModeInt) {
860 case DomainsDatabaseHelper.SYSTEM_DEFAULT:
861 if (defaultNightMode) { // Night mode enabled by default.
862 // Set the icon according to the theme.
864 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_dark));
866 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_light));
868 } else { // Night mode disabled by default.
869 // Set the icon according to the theme.
871 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_dark));
873 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_light));
877 // Show night mode TextView.
878 nightModeTextView.setVisibility(View.VISIBLE);
881 case DomainsDatabaseHelper.ENABLED:
882 // Set the icon according to the theme.
884 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_dark));
886 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_light));
889 // Hide the night mode TextView.
890 nightModeTextView.setVisibility(View.GONE);
893 case DomainsDatabaseHelper.DISABLED:
894 // Set the icon according to the theme.
896 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_dark));
898 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_light));
901 // Hide the night mode TextView.
902 nightModeTextView.setVisibility(View.GONE);
906 // Open the night mode spinner when the TextView is clicked.
907 nightModeTextView.setOnClickListener((View v) -> {
908 // Open the night mode spinner.
909 nightModeSpinner.performClick();
912 // Display the wide viewport in the spinner.
913 wideViewportSpinner.setSelection(wideViewportInt);
915 // Set the default wide viewport text.
916 if (defaultWideViewport) {
917 wideViewportTextView.setText(wideViewportArrayAdapter.getItem(DomainsDatabaseHelper.ENABLED));
919 wideViewportTextView.setText(wideViewportArrayAdapter.getItem(DomainsDatabaseHelper.DISABLED));
922 // 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.
923 switch (wideViewportInt) {
924 case DomainsDatabaseHelper.SYSTEM_DEFAULT:
925 if (defaultWideViewport) { // Wide viewport enabled by default.
926 // Set the icon according to the theme.
928 wideViewportImageView.setImageDrawable(resources.getDrawable(R.drawable.wide_viewport_enabled_dark));
930 wideViewportImageView.setImageDrawable(resources.getDrawable(R.drawable.wide_viewport_enabled_light));
932 } else { // Wide viewport disabled by default.
934 wideViewportImageView.setImageDrawable(resources.getDrawable(R.drawable.wide_viewport_disabled_dark));
936 wideViewportImageView.setImageDrawable(resources.getDrawable(R.drawable.wide_viewport_disabled_light));
940 // Show the wide viewport text view.
941 wideViewportTextView.setVisibility(View.VISIBLE);
944 case DomainsDatabaseHelper.ENABLED:
945 // Set the icon according to the theme.
947 wideViewportImageView.setImageDrawable(resources.getDrawable(R.drawable.wide_viewport_enabled_dark));
949 wideViewportImageView.setImageDrawable(resources.getDrawable(R.drawable.wide_viewport_enabled_light));
952 // Hide the wide viewport text view.
953 wideViewportTextView.setVisibility(View.GONE);
956 case DomainsDatabaseHelper.DISABLED:
957 // Set the icon according to the theme.
959 wideViewportImageView.setImageDrawable(resources.getDrawable(R.drawable.wide_viewport_disabled_dark));
961 wideViewportImageView.setImageDrawable(resources.getDrawable(R.drawable.wide_viewport_disabled_light));
964 // Hide the wide viewport text view.
965 wideViewportTextView.setVisibility(View.GONE);
969 // Open the wide viewport spinner when the text view is clicked.
970 wideViewportTextView.setOnClickListener((View view) -> {
971 // Open the wide viewport spinner.
972 wideViewportSpinner.performClick();
975 // Display the website images mode in the spinner.
976 displayWebpageImagesSpinner.setSelection(displayImagesInt);
978 // Set the default display images text.
979 if (defaultDisplayWebpageImages) {
980 displayImagesTextView.setText(displayImagesArrayAdapter.getItem(DomainsDatabaseHelper.ENABLED));
982 displayImagesTextView.setText(displayImagesArrayAdapter.getItem(DomainsDatabaseHelper.DISABLED));
985 // 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.
986 switch (displayImagesInt) {
987 case DomainsDatabaseHelper.SYSTEM_DEFAULT:
988 if (defaultDisplayWebpageImages) { // Display webpage images enabled by default.
989 // Set the icon according to the theme.
991 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_dark));
993 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_light));
995 } else { // Display webpage images disabled by default.
996 // Set the icon according to the theme.
998 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_dark));
1000 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_light));
1004 // Show the display images text view.
1005 displayImagesTextView.setVisibility(View.VISIBLE);
1008 case DomainsDatabaseHelper.ENABLED:
1009 // Set the icon according to the theme.
1011 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_dark));
1013 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_light));
1016 // Hide the display images text view.
1017 displayImagesTextView.setVisibility(View.GONE);
1020 case DomainsDatabaseHelper.DISABLED:
1021 // Set the icon according to the theme.
1023 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_dark));
1025 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_light));
1028 // Hide the display images text view.
1029 displayImagesTextView.setVisibility(View.GONE);
1033 // Open the display images spinner when the text view is clicked.
1034 displayImagesTextView.setOnClickListener((View view) -> {
1035 // Open the user agent spinner.
1036 displayWebpageImagesSpinner.performClick();
1039 // Set the pinned SSL certificate icon.
1040 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.
1041 // Check the switch.
1042 pinnedSslCertificateSwitch.setChecked(true);
1044 // Set the icon according to the theme.
1046 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_dark));
1048 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_light));
1050 } else { // Pinned SSL certificate is disabled.
1051 // Uncheck the switch.
1052 pinnedSslCertificateSwitch.setChecked(false);
1054 // Set the icon according to the theme.
1056 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_dark));
1058 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_light));
1062 // Store the current date.
1063 Date currentDate = Calendar.getInstance().getTime();
1065 // Setup the string builders to display the general certificate information in blue. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
1066 savedSslIssuedToONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), savedSslIssuedToONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1067 savedSslIssuedToUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), savedSslIssuedToUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1068 savedSslIssuedByCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), savedSslIssuedByCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1069 savedSslIssuedByONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), savedSslIssuedByONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1070 savedSslIssuedByUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), savedSslIssuedByUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1072 // Check the certificate Common Name against the domain name.
1073 boolean savedSslCommonNameMatchesDomainName = checkDomainNameAgainstCertificate(domainNameString, savedSslIssuedToCNameString);
1075 // Format the issued to Common Name color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
1076 if (savedSslCommonNameMatchesDomainName) {
1077 savedSslIssuedToCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), savedSslIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1079 savedSslIssuedToCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), savedSslIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1082 // Format the start date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
1083 if ((savedSslStartDate != null) && savedSslStartDate.after(currentDate)) { // The certificate start date is in the future.
1084 savedSslStartDateStringBuilder.setSpan(redColorSpan, startDateLabel.length(), savedSslStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1085 } else { // The certificate start date is in the past.
1086 savedSslStartDateStringBuilder.setSpan(blueColorSpan, startDateLabel.length(), savedSslStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1089 // Format the end date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
1090 if ((savedSslEndDate != null) && savedSslEndDate.before(currentDate)) { // The certificate end date is in the past.
1091 savedSslEndDateStringBuilder.setSpan(redColorSpan, endDateLabel.length(), savedSslEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1092 } else { // The certificate end date is in the future.
1093 savedSslEndDateStringBuilder.setSpan(blueColorSpan, endDateLabel.length(), savedSslEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1096 // Display the saved website SSL certificate strings.
1097 savedSslIssuedToCNameTextView.setText(savedSslIssuedToCNameStringBuilder);
1098 savedSslIssuedToONameTextView.setText(savedSslIssuedToONameStringBuilder);
1099 savedSslIssuedToUNameTextView.setText(savedSslIssuedToUNameStringBuilder);
1100 savedSslIssuedByCNameTextView.setText(savedSslIssuedByCNameStringBuilder);
1101 savedSslIssuedByONameTextView.setText(savedSslIssuedByONameStringBuilder);
1102 savedSslIssuedByUNameTextView.setText(savedSslIssuedByUNameStringBuilder);
1103 savedSslStartDateTextView.setText(savedSslStartDateStringBuilder);
1104 savedSslEndDateTextView.setText(savedSslEndDateStringBuilder);
1106 // Populate the current website SSL certificate if there is one.
1107 if (DomainsActivity.sslIssuedToCName != null) {
1108 // Get dates from the raw long values.
1109 Date currentSslStartDate = new Date(DomainsActivity.sslStartDateLong);
1110 Date currentSslEndDate = new Date(DomainsActivity.sslEndDateLong);
1112 // Create a spannable string builder for each text view that needs multiple colors of text.
1113 SpannableStringBuilder currentSslIssuedToCNameStringBuilder = new SpannableStringBuilder(cNameLabel + DomainsActivity.sslIssuedToCName);
1114 SpannableStringBuilder currentSslIssuedToONameStringBuilder = new SpannableStringBuilder(oNameLabel + DomainsActivity.sslIssuedToOName);
1115 SpannableStringBuilder currentSslIssuedToUNameStringBuilder = new SpannableStringBuilder(uNameLabel + DomainsActivity.sslIssuedToUName);
1116 SpannableStringBuilder currentSslIssuedByCNameStringBuilder = new SpannableStringBuilder(cNameLabel + DomainsActivity.sslIssuedByCName);
1117 SpannableStringBuilder currentSslIssuedByONameStringBuilder = new SpannableStringBuilder(oNameLabel + DomainsActivity.sslIssuedByOName);
1118 SpannableStringBuilder currentSslIssuedByUNameStringBuilder = new SpannableStringBuilder(uNameLabel + DomainsActivity.sslIssuedByUName);
1119 SpannableStringBuilder currentSslStartDateStringBuilder = new SpannableStringBuilder(startDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG)
1120 .format(currentSslStartDate));
1121 SpannableStringBuilder currentSslEndDateStringBuilder = new SpannableStringBuilder(endDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG)
1122 .format(currentSslEndDate));
1124 // Setup the string builders to display the general certificate information in blue. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
1125 currentSslIssuedToONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), currentSslIssuedToONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1126 currentSslIssuedToUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), currentSslIssuedToUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1127 currentSslIssuedByCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), currentSslIssuedByCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1128 currentSslIssuedByONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), currentSslIssuedByONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1129 currentSslIssuedByUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), currentSslIssuedByUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1131 // Check the certificate Common Name against the domain name.
1132 boolean currentSslCommonNameMatchesDomainName = checkDomainNameAgainstCertificate(domainNameString, DomainsActivity.sslIssuedToCName);
1134 // Format the issued to Common Name color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
1135 if (currentSslCommonNameMatchesDomainName) {
1136 currentSslIssuedToCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), currentSslIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1138 currentSslIssuedToCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), currentSslIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1141 // Format the start date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
1142 if (currentSslStartDate.after(currentDate)) { // The certificate start date is in the future.
1143 currentSslStartDateStringBuilder.setSpan(redColorSpan, startDateLabel.length(), currentSslStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1144 } else { // The certificate start date is in the past.
1145 currentSslStartDateStringBuilder.setSpan(blueColorSpan, startDateLabel.length(), currentSslStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1148 // Format the end date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
1149 if (currentSslEndDate.before(currentDate)) { // The certificate end date is in the past.
1150 currentSslEndDateStringBuilder.setSpan(redColorSpan, endDateLabel.length(), currentSslEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1151 } else { // The certificate end date is in the future.
1152 currentSslEndDateStringBuilder.setSpan(blueColorSpan, endDateLabel.length(), currentSslEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1155 // Display the current website SSL certificate strings.
1156 currentSslIssuedToCNameTextView.setText(currentSslIssuedToCNameStringBuilder);
1157 currentSslIssuedToONameTextView.setText(currentSslIssuedToONameStringBuilder);
1158 currentSslIssuedToUNameTextView.setText(currentSslIssuedToUNameStringBuilder);
1159 currentSslIssuedByCNameTextView.setText(currentSslIssuedByCNameStringBuilder);
1160 currentSslIssuedByONameTextView.setText(currentSslIssuedByONameStringBuilder);
1161 currentSslIssuedByUNameTextView.setText(currentSslIssuedByUNameStringBuilder);
1162 currentSslStartDateTextView.setText(currentSslStartDateStringBuilder);
1163 currentSslEndDateTextView.setText(currentSslEndDateStringBuilder);
1166 // Set the initial display status of the SSL certificates card views.
1167 if (pinnedSslCertificateSwitch.isChecked()) { // An SSL certificate is pinned.
1168 // Set the visibility of the saved SSL certificate.
1169 if (savedSslIssuedToCNameString == null) {
1170 savedSslCardView.setVisibility(View.GONE);
1172 savedSslCardView.setVisibility(View.VISIBLE);
1175 // Set the visibility of the current website SSL certificate.
1176 if (DomainsActivity.sslIssuedToCName == null) { // There is no current SSL certificate.
1177 // Hide the SSL certificate.
1178 currentSslCardView.setVisibility(View.GONE);
1180 // Show the instruction.
1181 noCurrentWebsiteCertificateTextView.setVisibility(View.VISIBLE);
1182 } else { // There is a current SSL certificate.
1183 // Show the SSL certificate.
1184 currentSslCardView.setVisibility(View.VISIBLE);
1186 // Hide the instruction.
1187 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
1190 // Set the status of the radio buttons and the card view backgrounds.
1191 if (savedSslCardView.getVisibility() == View.VISIBLE) { // The saved SSL certificate is displayed.
1192 // Check the saved SSL certificate radio button.
1193 savedSslCertificateRadioButton.setChecked(true);
1195 // Uncheck the current website SSL certificate radio button.
1196 currentWebsiteCertificateRadioButton.setChecked(false);
1198 // Darken the background of the current website SSL certificate linear layout according to the theme.
1200 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1202 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1204 } else if (currentSslCardView.getVisibility() == View.VISIBLE) { // The saved SSL certificate is hidden but the current website SSL certificate is visible.
1205 // Check the current website SSL certificate radio button.
1206 currentWebsiteCertificateRadioButton.setChecked(true);
1208 // Uncheck the saved SSL certificate radio button.
1209 savedSslCertificateRadioButton.setChecked(false);
1210 } else { // Neither SSL certificate is visible.
1211 // Uncheck both radio buttons.
1212 savedSslCertificateRadioButton.setChecked(false);
1213 currentWebsiteCertificateRadioButton.setChecked(false);
1215 } else { // An SSL certificate is not pinned.
1216 // Hide the SSl certificates and instructions.
1217 savedSslCardView.setVisibility(View.GONE);
1218 currentSslCardView.setVisibility(View.GONE);
1219 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
1221 // Uncheck the radio buttons.
1222 savedSslCertificateRadioButton.setChecked(false);
1223 currentWebsiteCertificateRadioButton.setChecked(false);
1226 // Set the pinned IP addresses icon.
1227 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.
1228 // Check the switch.
1229 pinnedIpAddressesSwitch.setChecked(true);
1231 // Set the icon according to the theme.
1233 pinnedIpAddressesImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_dark));
1235 pinnedIpAddressesImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_light));
1237 } else { // Pinned IP Addresses is disabled.
1238 // Uncheck the switch.
1239 pinnedIpAddressesSwitch.setChecked(false);
1241 // Set the icon according to the theme.
1243 pinnedIpAddressesImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_dark));
1245 pinnedIpAddressesImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_light));
1249 // Populate the saved and current IP addresses.
1250 savedIpAddressesTextView.setText(savedIpAddresses);
1251 currentIpAddressesTextView.setText(DomainsActivity.currentIpAddresses);
1253 // Set the initial display status of the IP addresses card views.
1254 if (pinnedIpAddressesSwitch.isChecked()) { // IP addresses are pinned.
1255 // Set the visibility of the saved IP addresses.
1256 if (savedIpAddresses == null) { // There are no saved IP addresses.
1257 savedIpAddressesCardView.setVisibility(View.GONE);
1258 } else { // There are saved IP addresses.
1259 savedIpAddressesCardView.setVisibility(View.VISIBLE);
1262 // Set the visibility of the current IP addresses.
1263 currentIpAddressesCardView.setVisibility(View.VISIBLE);
1265 // Set the status of the radio buttons and the card view backgrounds.
1266 if (savedIpAddressesCardView.getVisibility() == View.VISIBLE) { // The saved IP addresses are displayed.
1267 // Check the saved IP addresses radio button.
1268 savedIpAddressesRadioButton.setChecked(true);
1270 // Uncheck the current IP addresses radio button.
1271 currentIpAddressesRadioButton.setChecked(false);
1273 // Darken the background of the current IP addresses linear layout according to the theme.
1275 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1277 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1279 } else { // The saved IP addresses are hidden.
1280 // Check the current IP addresses radio button.
1281 currentIpAddressesRadioButton.setChecked(true);
1283 // Uncheck the saved IP addresses radio button.
1284 savedIpAddressesRadioButton.setChecked(false);
1286 } else { // IP addresses are not pinned.
1287 // Hide the IP addresses card views.
1288 savedIpAddressesCardView.setVisibility(View.GONE);
1289 currentIpAddressesCardView.setVisibility(View.GONE);
1291 // Uncheck the radio buttons.
1292 savedIpAddressesRadioButton.setChecked(false);
1293 currentIpAddressesRadioButton.setChecked(false);
1297 // Set the JavaScript switch listener.
1298 javaScriptSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1299 if (isChecked) { // JavaScript is enabled.
1300 // Update the JavaScript icon.
1301 javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.javascript_enabled));
1303 // Enable the DOM storage `Switch`.
1304 domStorageSwitch.setEnabled(true);
1306 // Update the DOM storage icon.
1307 if (domStorageSwitch.isChecked()) { // DOM storage is enabled.
1308 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_enabled));
1309 } else { // DOM storage is disabled.
1310 // Set the icon according to the theme.
1312 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_dark));
1314 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_light));
1317 } else { // JavaScript is disabled.
1318 // Update the JavaScript icon.
1319 javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.privacy_mode));
1321 // Disable the DOM storage `Switch`.
1322 domStorageSwitch.setEnabled(false);
1324 // Set the DOM storage icon according to the theme.
1326 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_dark));
1328 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_light));
1333 // Set the first-party cookies switch listener.
1334 firstPartyCookiesSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1335 if (isChecked) { // First-party cookies are enabled.
1336 // Update the first-party cookies icon.
1337 firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_enabled));
1339 // Enable the third-party cookies switch.
1340 thirdPartyCookiesSwitch.setEnabled(true);
1342 // Update the third-party cookies icon.
1343 if (thirdPartyCookiesSwitch.isChecked()) { // Third-party cookies are enabled.
1344 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_warning));
1345 } else { // Third-party cookies are disabled.
1346 // Set the third-party cookies icon according to the theme.
1348 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_dark));
1350 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_light));
1353 } else { // First-party cookies are disabled.
1354 // Update the first-party cookies icon according to the theme.
1356 firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_dark));
1358 firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_light));
1361 // Disable the third-party cookies switch.
1362 thirdPartyCookiesSwitch.setEnabled(false);
1364 // Set the third-party cookies icon according to the theme.
1366 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_ghosted_dark));
1368 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_ghosted_light));
1373 // Set the third-party cookies switch listener.
1374 thirdPartyCookiesSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1377 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_warning));
1379 // Update the third-party cookies icon according to the theme.
1381 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_dark));
1383 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_light));
1388 // Set the DOM Storage switch listener.
1389 domStorageSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1392 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_enabled));
1394 // Set the icon according to the theme.
1396 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_dark));
1398 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_light));
1403 // Set the form data switch listener. It can be removed once the minimum API >= 26.
1404 if (Build.VERSION.SDK_INT < 26) {
1405 formDataSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1408 formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_enabled));
1410 // Set the icon according to the theme.
1412 formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_disabled_dark));
1414 formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_disabled_light));
1420 // Set the EasyList switch listener.
1421 easyListSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1423 if (isChecked) { // EasyList is on.
1424 // Set the icon according to the theme.
1426 easyListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_enabled_dark));
1428 easyListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_enabled_light));
1430 } else { // EasyList is off.
1431 // Set the icon according to the theme.
1433 easyListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_disabled_dark));
1435 easyListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_disabled_light));
1440 // Set the EasyPrivacy switch listener.
1441 easyPrivacySwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1443 if (isChecked) { // EasyPrivacy is on.
1444 // Set the icon according to the theme.
1446 easyPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_enabled_dark));
1448 easyPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_enabled_light));
1450 } else { // EasyPrivacy is off.
1451 // Set the icon according to the theme.
1453 easyPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_disabled_dark));
1455 easyPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_disabled_light));
1460 // Set the Fanboy's Annoyance List switch listener.
1461 fanboysAnnoyanceListSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1462 // Update the icon and Fanboy's Social Blocking List.
1463 if (isChecked) { // Fanboy's Annoyance List is on.
1464 // Set the icon according to the theme.
1466 fanboysAnnoyanceListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_dark));
1468 fanboysAnnoyanceListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_light));
1471 // Disable the Fanboy's Social Blocking List switch.
1472 fanboysSocialBlockingListSwitch.setEnabled(false);
1474 // Update the Fanboy's Social Blocking List icon according to the theme.
1476 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_ghosted_dark));
1478 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_ghosted_light));
1480 } else { // Fanboy's Annoyance List is off.
1481 // Set the icon according to the theme.
1483 fanboysAnnoyanceListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_dark));
1485 fanboysAnnoyanceListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_light));
1488 // Enable the Fanboy's Social Blocking List switch.
1489 fanboysSocialBlockingListSwitch.setEnabled(true);
1491 // Update the Fanboy's Social Blocking List icon.
1492 if (fanboysSocialBlockingListSwitch.isChecked()) { // Fanboy's Social Blocking List is on.
1493 // Update the icon according to the theme.
1495 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_dark));
1497 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_light));
1499 } else { // Fanboy's Social Blocking List is off.
1500 // Update the icon according to the theme.
1502 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_dark));
1504 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_light));
1511 // Set the Fanboy's Social Blocking List switch listener.
1512 fanboysSocialBlockingListSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1514 if (isChecked) { // Fanboy's Social Blocking List is on.
1515 // Set the icon according to the theme.
1517 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_dark));
1519 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_light));
1521 } else { // Fanboy's Social Blocking List is off.
1522 // Set the icon according to the theme.
1524 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_dark));
1526 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_light));
1531 // Set the UltraList switch listener.
1532 ultraListSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1534 if (isChecked) { // UltraList is on.
1535 // Set the icon according to the theme.
1537 ultraListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_enabled_dark));
1539 ultraListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_enabled_light));
1541 } else { // UltraList is off.
1542 // Set the icon according to the theme.
1544 ultraListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_disabled_dark));
1546 ultraListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_disabled_light));
1551 // Set the UltraPrivacy switch listener.
1552 ultraPrivacySwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1554 if (isChecked) { // UltraPrivacy is on.
1555 // Set the icon according to the theme.
1557 ultraPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_enabled_dark));
1559 ultraPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_enabled_light));
1561 } else { // UltraPrivacy is off.
1562 // Set the icon according to the theme.
1564 ultraPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_disabled_dark));
1566 ultraPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_disabled_light));
1571 // Set the block all third-party requests switch listener.
1572 blockAllThirdPartyRequestsSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1574 if (isChecked) { // Blocking all third-party requests is on.
1575 // Set the icon according to the theme.
1577 blockAllThirdPartyRequestsImageView.setImageDrawable(resources.getDrawable(R.drawable.block_all_third_party_requests_enabled_dark));
1579 blockAllThirdPartyRequestsImageView.setImageDrawable(resources.getDrawable(R.drawable.block_all_third_party_requests_enabled_light));
1581 } else { // Blocking all third-party requests is off.
1582 // Set the icon according to the theme.
1584 blockAllThirdPartyRequestsImageView.setImageDrawable(resources.getDrawable(R.drawable.block_all_third_party_requests_disabled_dark));
1586 blockAllThirdPartyRequestsImageView.setImageDrawable(resources.getDrawable(R.drawable.block_all_third_party_requests_disabled_light));
1591 // Set the user agent spinner listener.
1592 userAgentSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1594 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1595 // Set the new user agent.
1597 case MainWebViewActivity.DOMAINS_SYSTEM_DEFAULT_USER_AGENT:
1598 // Show the user agent TextView.
1599 userAgentTextView.setVisibility(View.VISIBLE);
1601 // Hide the custom user agent EditText.
1602 customUserAgentEditText.setVisibility(View.GONE);
1604 // Set the user text.
1605 switch (defaultUserAgentArrayPosition) {
1606 case MainWebViewActivity.UNRECOGNIZED_USER_AGENT: // The default user agent name is not on the canonical list.
1607 // This is probably because it was set in an older version of Privacy Browser before the switch to persistent user agent names.
1608 userAgentTextView.setText(defaultUserAgentName);
1611 case MainWebViewActivity.SETTINGS_WEBVIEW_DEFAULT_USER_AGENT:
1612 // Display the `WebView` default user agent.
1613 userAgentTextView.setText(webViewDefaultUserAgentString);
1616 case MainWebViewActivity.SETTINGS_CUSTOM_USER_AGENT:
1617 // Display the custom user agent.
1618 userAgentTextView.setText(defaultCustomUserAgentString);
1622 // Get the user agent string from the user agent data array.
1623 userAgentTextView.setText(userAgentDataArray[defaultUserAgentArrayPosition]);
1627 case MainWebViewActivity.DOMAINS_WEBVIEW_DEFAULT_USER_AGENT:
1628 // Show the user agent TextView and set the text.
1629 userAgentTextView.setVisibility(View.VISIBLE);
1630 userAgentTextView.setText(webViewDefaultUserAgentString);
1632 // Hide the custom user agent EditTex.
1633 customUserAgentEditText.setVisibility(View.GONE);
1636 case MainWebViewActivity.DOMAINS_CUSTOM_USER_AGENT:
1637 // Hide the user agent TextView.
1638 userAgentTextView.setVisibility(View.GONE);
1640 // Show the custom user agent EditText and set the current user agent name as the text.
1641 customUserAgentEditText.setVisibility(View.VISIBLE);
1642 customUserAgentEditText.setText(currentUserAgentName);
1646 // 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.
1647 userAgentTextView.setVisibility(View.VISIBLE);
1648 userAgentTextView.setText(userAgentDataArray[position - 1]);
1650 // Hide `customUserAgentEditText`.
1651 customUserAgentEditText.setVisibility(View.GONE);
1656 public void onNothingSelected(AdapterView<?> parent) {
1661 // Set the font size spinner listener.
1662 fontSizeSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1664 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1665 // Update the display options for `fontSizeTextView`.
1666 if (position == 0) { // System default font size has been selected. Display `fontSizeTextView`.
1667 fontSizeTextView.setVisibility(View.VISIBLE);
1668 } else { // A custom font size has been selected. Hide `fontSizeTextView`.
1669 fontSizeTextView.setVisibility(View.GONE);
1674 public void onNothingSelected(AdapterView<?> parent) {
1679 // Set the swipe to refresh spinner listener.
1680 swipeToRefreshSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1682 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1683 // 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.
1685 case DomainsDatabaseHelper.SYSTEM_DEFAULT:
1686 if (defaultSwipeToRefresh) { // Swipe to refresh enabled by default.
1687 // Set the icon according to the theme.
1689 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_enabled_dark));
1691 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_enabled_light));
1693 } else { // Swipe to refresh disabled by default.
1694 // Set the icon according to the theme.
1696 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_disabled_dark));
1698 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_disabled_light));
1702 // Show the swipe to refresh TextView.
1703 swipeToRefreshTextView.setVisibility(View.VISIBLE);
1706 case DomainsDatabaseHelper.ENABLED:
1707 // Set the icon according to the theme.
1709 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_enabled_dark));
1711 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_enabled_light));
1714 // Hide the swipe to refresh TextView.
1715 swipeToRefreshTextView.setVisibility(View.GONE);
1718 case DomainsDatabaseHelper.DISABLED:
1719 // Set the icon according to the theme.
1721 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_disabled_dark));
1723 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_disabled_light));
1726 // Hide the swipe to refresh TextView.
1727 swipeToRefreshTextView.setVisibility(View.GONE);
1732 public void onNothingSelected(AdapterView<?> parent) {
1737 // Set the night mode spinner listener.
1738 nightModeSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1740 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1741 // 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.
1743 case DomainsDatabaseHelper.SYSTEM_DEFAULT:
1744 if (defaultNightMode) { // Night mode enabled by default.
1745 // Set the icon according to the theme.
1747 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_dark));
1749 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_light));
1751 } else { // Night mode disabled by default.
1752 // Set the icon according to the theme.
1754 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_dark));
1756 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_light));
1760 // Show the night mode TextView.
1761 nightModeTextView.setVisibility(View.VISIBLE);
1764 case DomainsDatabaseHelper.ENABLED:
1765 // Set the icon according to the theme.
1767 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_dark));
1769 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_light));
1772 // Hide `nightModeTextView`.
1773 nightModeTextView.setVisibility(View.GONE);
1776 case DomainsDatabaseHelper.DISABLED:
1777 // Set the icon according to the theme.
1779 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_dark));
1781 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_light));
1784 // Hide `nightModeTextView`.
1785 nightModeTextView.setVisibility(View.GONE);
1789 // Create a boolean to store the current night mode setting.
1790 boolean currentNightModeEnabled = (position == DomainsDatabaseHelper.ENABLED) || ((position == DomainsDatabaseHelper.SYSTEM_DEFAULT) && defaultNightMode);
1792 // Disable the JavaScript switch if night mode is enabled.
1793 if (currentNightModeEnabled) {
1794 javaScriptSwitch.setEnabled(false);
1796 javaScriptSwitch.setEnabled(true);
1799 // Update the JavaScript icon.
1800 if ((javaScriptInt == 1) || currentNightModeEnabled) {
1801 javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.javascript_enabled));
1803 javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.privacy_mode));
1806 // Update the DOM storage status.
1807 if ((javaScriptInt == 1) || currentNightModeEnabled) { // JavaScript is enabled.
1808 // Enable the DOM storage `Switch`.
1809 domStorageSwitch.setEnabled(true);
1811 // Set the DOM storage status. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
1812 if (domStorageInt == 1) { // Both JavaScript and DOM storage are enabled.
1813 domStorageSwitch.setChecked(true);
1814 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_enabled));
1815 } else { // JavaScript is enabled but DOM storage is disabled.
1816 // Set the DOM storage switch to off.
1817 domStorageSwitch.setChecked(false);
1819 // Set the icon according to the theme.
1821 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_dark));
1823 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_light));
1826 } else { // JavaScript is disabled.
1827 // Disable the DOM storage `Switch`.
1828 domStorageSwitch.setEnabled(false);
1830 // Set the checked status of DOM storage.
1831 if (domStorageInt == 1) { // DOM storage is enabled but JavaScript is disabled.
1832 domStorageSwitch.setChecked(true);
1833 } else { // Both JavaScript and DOM storage are disabled.
1834 domStorageSwitch.setChecked(false);
1837 // Set the icon according to the theme.
1839 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_dark));
1841 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_light));
1847 public void onNothingSelected(AdapterView<?> parent) {
1852 // Set the wide viewport spinner listener.
1853 wideViewportSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1855 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1856 // Update the icon and the visibility of the wide viewport text view.
1858 case DomainsDatabaseHelper.SYSTEM_DEFAULT:
1859 if (defaultWideViewport) { // Wide viewport is enabled by default.
1860 // Set the icon according to the theme.
1862 wideViewportImageView.setImageDrawable(resources.getDrawable(R.drawable.wide_viewport_enabled_dark));
1864 wideViewportImageView.setImageDrawable(resources.getDrawable(R.drawable.wide_viewport_enabled_light));
1866 } else { // Wide viewport is disabled by default.
1868 wideViewportImageView.setImageDrawable(resources.getDrawable(R.drawable.wide_viewport_disabled_dark));
1870 wideViewportImageView.setImageDrawable(resources.getDrawable(R.drawable.wide_viewport_disabled_light));
1874 // Show the wide viewport text view.
1875 wideViewportTextView.setVisibility(View.VISIBLE);
1878 case DomainsDatabaseHelper.ENABLED:
1879 // Set the icon according to the theme.
1881 wideViewportImageView.setImageDrawable(resources.getDrawable(R.drawable.wide_viewport_enabled_dark));
1883 wideViewportImageView.setImageDrawable(resources.getDrawable(R.drawable.wide_viewport_enabled_light));
1886 // Hide the wide viewport text view.
1887 wideViewportTextView.setVisibility(View.GONE);
1890 case DomainsDatabaseHelper.DISABLED:
1891 // Set the icon according to the theme.
1893 wideViewportImageView.setImageDrawable(resources.getDrawable(R.drawable.wide_viewport_disabled_dark));
1895 wideViewportImageView.setImageDrawable(resources.getDrawable(R.drawable.wide_viewport_disabled_light));
1898 // Hid ethe wide viewport text view.
1899 wideViewportTextView.setVisibility(View.GONE);
1905 public void onNothingSelected(AdapterView<?> parent) {
1910 // Set the display webpage images spinner listener.
1911 displayWebpageImagesSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1913 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1914 // Update the icon and the visibility of the display images text view.
1916 case DomainsDatabaseHelper.SYSTEM_DEFAULT:
1917 if (defaultDisplayWebpageImages) { // Display webpage images is enabled by default.
1918 // Set the icon according to the theme.
1920 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_dark));
1922 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_light));
1924 } else { // Display webpage images is disabled by default.
1925 // Set the icon according to the theme.
1927 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_dark));
1929 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_light));
1933 // Show the display images text view.
1934 displayImagesTextView.setVisibility(View.VISIBLE);
1937 case DomainsDatabaseHelper.ENABLED:
1938 // Set the icon according to the theme.
1940 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_dark));
1942 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_light));
1945 // Hide the display images text view.
1946 displayImagesTextView.setVisibility(View.GONE);
1949 case DomainsDatabaseHelper.DISABLED:
1950 // Set the icon according to the theme.
1952 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_dark));
1954 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_light));
1957 // Hide the display images text view.
1958 displayImagesTextView.setVisibility(View.GONE);
1964 public void onNothingSelected(AdapterView<?> parent) {
1969 // Set the pinned SSL certificate switch listener.
1970 pinnedSslCertificateSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1972 if (isChecked) { // SSL certificate pinning is enabled.
1973 // Set the icon according to the theme.
1975 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_dark));
1977 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_light));
1980 // Update the visibility of the saved SSL certificate.
1981 if (savedSslIssuedToCNameString == null) {
1982 savedSslCardView.setVisibility(View.GONE);
1984 savedSslCardView.setVisibility(View.VISIBLE);
1987 // Update the visibility of the current website SSL certificate.
1988 if (DomainsActivity.sslIssuedToCName == null) {
1989 // Hide the SSL certificate.
1990 currentSslCardView.setVisibility(View.GONE);
1992 // Show the instruction.
1993 noCurrentWebsiteCertificateTextView.setVisibility(View.VISIBLE);
1995 // Show the SSL certificate.
1996 currentSslCardView.setVisibility(View.VISIBLE);
1998 // Hide the instruction.
1999 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
2002 // Set the status of the radio buttons.
2003 if (savedSslCardView.getVisibility() == View.VISIBLE) { // The saved SSL certificate is displayed.
2004 // Check the saved SSL certificate radio button.
2005 savedSslCertificateRadioButton.setChecked(true);
2007 // Uncheck the current website SSL certificate radio button.
2008 currentWebsiteCertificateRadioButton.setChecked(false);
2010 // Set the background of the saved SSL certificate linear layout to be transparent.
2011 savedSslCertificateLinearLayout.setBackgroundResource(R.color.transparent);
2013 // Darken the background of the current website SSL certificate linear layout according to the theme.
2015 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2017 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2020 // Scroll to the current website SSL certificate card.
2021 savedSslCardView.getParent().requestChildFocus(savedSslCardView, savedSslCardView);
2022 } else if (currentSslCardView.getVisibility() == View.VISIBLE) { // The saved SSL certificate is hidden but the current website SSL certificate is visible.
2023 // Check the current website SSL certificate radio button.
2024 currentWebsiteCertificateRadioButton.setChecked(true);
2026 // Uncheck the saved SSL certificate radio button.
2027 savedSslCertificateRadioButton.setChecked(false);
2029 // Set the background of the current website SSL certificate linear layout to be transparent.
2030 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.transparent);
2032 // Darken the background of the saved SSL certificate linear layout according to the theme.
2034 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2036 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2039 // Scroll to the current website SSL certificate card.
2040 currentSslCardView.getParent().requestChildFocus(currentSslCardView, currentSslCardView);
2041 } else { // Neither SSL certificate is visible.
2042 // Uncheck both radio buttons.
2043 savedSslCertificateRadioButton.setChecked(false);
2044 currentWebsiteCertificateRadioButton.setChecked(false);
2046 // Scroll to the current website SSL certificate card.
2047 noCurrentWebsiteCertificateTextView.getParent().requestChildFocus(noCurrentWebsiteCertificateTextView, noCurrentWebsiteCertificateTextView);
2049 } else { // SSL certificate pinning is disabled.
2050 // Set the icon according to the theme.
2052 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_dark));
2054 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_light));
2057 // Hide the SSl certificates and instructions.
2058 savedSslCardView.setVisibility(View.GONE);
2059 currentSslCardView.setVisibility(View.GONE);
2060 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
2062 // Uncheck the radio buttons.
2063 savedSslCertificateRadioButton.setChecked(false);
2064 currentWebsiteCertificateRadioButton.setChecked(false);
2068 savedSslCardView.setOnClickListener((View view) -> {
2069 // Check the saved SSL certificate radio button.
2070 savedSslCertificateRadioButton.setChecked(true);
2072 // Uncheck the current website SSL certificate radio button.
2073 currentWebsiteCertificateRadioButton.setChecked(false);
2075 // Set the background of the saved SSL certificate linear layout to be transparent.
2076 savedSslCertificateLinearLayout.setBackgroundResource(R.color.transparent);
2078 // Darken the background of the current website SSL certificate linear layout according to the theme.
2080 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2082 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2086 savedSslCertificateRadioButton.setOnClickListener((View view) -> {
2087 // Check the saved SSL certificate radio button.
2088 savedSslCertificateRadioButton.setChecked(true);
2090 // Uncheck the current website SSL certificate radio button.
2091 currentWebsiteCertificateRadioButton.setChecked(false);
2093 // Set the background of the saved SSL certificate linear layout to be transparent.
2094 savedSslCertificateLinearLayout.setBackgroundResource(R.color.transparent);
2096 // Darken the background of the current website SSL certificate linear layout according to the theme.
2098 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2100 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2104 currentSslCardView.setOnClickListener((View view) -> {
2105 // Check the current website SSL certificate radio button.
2106 currentWebsiteCertificateRadioButton.setChecked(true);
2108 // Uncheck the saved SSL certificate radio button.
2109 savedSslCertificateRadioButton.setChecked(false);
2111 // Set the background of the current website SSL certificate linear layout to be transparent.
2112 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.transparent);
2114 // Darken the background of the saved SSL certificate linear layout according to the theme.
2116 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2118 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2122 currentWebsiteCertificateRadioButton.setOnClickListener((View view) -> {
2123 // Check the current website SSL certificate radio button.
2124 currentWebsiteCertificateRadioButton.setChecked(true);
2126 // Uncheck the saved SSL certificate radio button.
2127 savedSslCertificateRadioButton.setChecked(false);
2129 // Set the background of the current website SSL certificate linear layout to be transparent.
2130 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.transparent);
2132 // Darken the background of the saved SSL certificate linear layout according to the theme.
2134 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2136 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2140 // Set the pinned IP addresses switch listener.
2141 pinnedIpAddressesSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
2143 if (isChecked) { // IP addresses pinning is enabled.
2144 // Set the icon according to the theme.
2146 pinnedIpAddressesImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_dark));
2148 pinnedIpAddressesImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_light));
2151 // Update the visibility of the saved IP addresses card view.
2152 if (savedIpAddresses == null) { // There are no saved IP addresses.
2153 savedIpAddressesCardView.setVisibility(View.GONE);
2154 } else { // There are saved IP addresses.
2155 savedIpAddressesCardView.setVisibility(View.VISIBLE);
2158 // Show the current IP addresses card view.
2159 currentIpAddressesCardView.setVisibility(View.VISIBLE);
2161 // Set the status of the radio buttons.
2162 if (savedIpAddressesCardView.getVisibility() == View.VISIBLE) { // The saved IP addresses are visible.
2163 // Check the saved IP addresses radio button.
2164 savedIpAddressesRadioButton.setChecked(true);
2166 // Uncheck the current IP addresses radio button.
2167 currentIpAddressesRadioButton.setChecked(false);
2169 // Set the background of the saved IP addresses linear layout to be transparent.
2170 savedSslCertificateLinearLayout.setBackgroundResource(R.color.transparent);
2172 // Darken the background of the current IP addresses linear layout according to the theme.
2174 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2176 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2178 } else { // The saved IP addresses are not visible.
2179 // Check the current IP addresses radio button.
2180 currentIpAddressesRadioButton.setChecked(true);
2182 // Uncheck the saved IP addresses radio button.
2183 savedIpAddressesRadioButton.setChecked(false);
2185 // Set the background of the current IP addresses linear layout to be transparent.
2186 currentIpAddressesLinearLayout.setBackgroundResource(R.color.transparent);
2188 // Darken the background of the saved IP addresses linear layout according to the theme.
2190 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2192 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2196 // Scroll to the bottom of the card views.
2197 currentIpAddressesCardView.getParent().requestChildFocus(currentIpAddressesCardView, currentIpAddressesCardView);
2198 } else { // IP addresses pinning is disabled.
2199 // Set the icon according to the theme.
2201 pinnedIpAddressesImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_dark));
2203 pinnedIpAddressesImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_light));
2206 // Hide the IP addresses card views.
2207 savedIpAddressesCardView.setVisibility(View.GONE);
2208 currentIpAddressesCardView.setVisibility(View.GONE);
2210 // Uncheck the radio buttons.
2211 savedIpAddressesRadioButton.setChecked(false);
2212 currentIpAddressesRadioButton.setChecked(false);
2216 savedIpAddressesCardView.setOnClickListener((View view) -> {
2217 // Check the saved IP addresses radio button.
2218 savedIpAddressesRadioButton.setChecked(true);
2220 // Uncheck the current website IP addresses radio button.
2221 currentIpAddressesRadioButton.setChecked(false);
2223 // Set the background of the saved IP addresses linear layout to be transparent.
2224 savedIpAddressesLinearLayout.setBackgroundResource(R.color.transparent);
2226 // Darken the background of the current IP addresses linear layout according to the theme.
2228 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2230 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2234 savedIpAddressesRadioButton.setOnClickListener((View view) -> {
2235 // Check the saved IP addresses radio button.
2236 savedIpAddressesRadioButton.setChecked(true);
2238 // Uncheck the current website IP addresses radio button.
2239 currentIpAddressesRadioButton.setChecked(false);
2241 // Set the background of the saved IP addresses linear layout to be transparent.
2242 savedIpAddressesLinearLayout.setBackgroundResource(R.color.transparent);
2244 // Darken the background of the current IP addresses linear layout according to the theme.
2246 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2248 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2252 currentIpAddressesCardView.setOnClickListener((View view) -> {
2253 // Check the current IP addresses radio button.
2254 currentIpAddressesRadioButton.setChecked(true);
2256 // Uncheck the saved IP addresses radio button.
2257 savedIpAddressesRadioButton.setChecked(false);
2259 // Set the background of the current IP addresses linear layout to be transparent.
2260 currentIpAddressesLinearLayout.setBackgroundResource(R.color.transparent);
2262 // Darken the background of the saved IP addresses linear layout according to the theme.
2264 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2266 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2270 currentIpAddressesRadioButton.setOnClickListener((View view) -> {
2271 // Check the current IP addresses radio button.
2272 currentIpAddressesRadioButton.setChecked(true);
2274 // Uncheck the saved IP addresses radio button.
2275 savedIpAddressesRadioButton.setChecked(false);
2277 // Set the background of the current IP addresses linear layout to be transparent.
2278 currentIpAddressesLinearLayout.setBackgroundResource(R.color.transparent);
2280 // Darken the background of the saved IP addresses linear layout according to the theme.
2282 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2284 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2288 return domainSettingsView;
2291 private boolean checkDomainNameAgainstCertificate(String domainName, String certificateCommonName) {
2292 // Initialize `domainNamesMatch`.
2293 boolean domainNamesMatch = false;
2295 // Check various wildcard permutations if `domainName` and `certificateCommonName` are not empty.
2296 // `noinspection ConstantCondition` removes Android Studio's incorrect lint warning that `domainName` can never be `null`.
2297 if ((domainName != null) && (certificateCommonName != null)) {
2298 // Check if the domains match.
2299 if (domainName.equals(certificateCommonName)) {
2300 domainNamesMatch = true;
2303 // If `domainName` starts with a wildcard, check the base domain against all the subdomains of `certificateCommonName`.
2304 if (!domainNamesMatch && domainName.startsWith("*.") && (domainName.length() > 2)) {
2305 // Remove the initial `*.`.
2306 String baseDomainName = domainName.substring(2);
2308 // Setup a copy of `certificateCommonName` to test subdomains.
2309 String certificateCommonNameSubdomain = certificateCommonName;
2311 // Check all the subdomains in `certificateCommonNameSubdomain` against `baseDomainName`.
2312 while (!domainNamesMatch && certificateCommonNameSubdomain.contains(".")) { // Stop checking if we know that `domainNamesMatch` is `true` or if we run out of `.`.
2313 // Test the `certificateCommonNameSubdomain` against `baseDomainName`.
2314 if (certificateCommonNameSubdomain.equals(baseDomainName)) {
2315 domainNamesMatch = true;
2318 // Strip out the lowest subdomain of `certificateCommonNameSubdomain`.
2320 certificateCommonNameSubdomain = certificateCommonNameSubdomain.substring(certificateCommonNameSubdomain.indexOf(".") + 1);
2321 } catch (IndexOutOfBoundsException e) { // `certificateCommonNameSubdomain` ends with `.`.
2322 certificateCommonNameSubdomain = "";
2327 // If `certificateCommonName` starts with a wildcard, check the base common name against all the subdomains of `domainName`.
2328 if (!domainNamesMatch && certificateCommonName.startsWith("*.") && (certificateCommonName.length() > 2)) {
2329 // Remove the initial `*.`.
2330 String baseCertificateCommonName = certificateCommonName.substring(2);
2332 // Setup a copy of `domainName` to test subdomains.
2333 String domainNameSubdomain = domainName;
2335 // Check all the subdomains in `domainNameSubdomain` against `baseCertificateCommonName`.
2336 while (!domainNamesMatch && domainNameSubdomain.contains(".") && (domainNameSubdomain.length() > 2)) {
2337 // Test the `domainNameSubdomain` against `baseCertificateCommonName`.
2338 if (domainNameSubdomain.equals(baseCertificateCommonName)) {
2339 domainNamesMatch = true;
2342 // Strip out the lowest subdomain of `domainNameSubdomain`.
2344 domainNameSubdomain = domainNameSubdomain.substring(domainNameSubdomain.indexOf(".") + 1);
2345 } catch (IndexOutOfBoundsException e) { // `domainNameSubdomain` ends with `.`.
2346 domainNameSubdomain = "";
2351 // If both names start with a wildcard, check if the root of one contains the root of the other.
2352 if (!domainNamesMatch && domainName.startsWith("*.") && (domainName.length() > 2) && certificateCommonName.startsWith("*.") && (certificateCommonName.length() > 2)) {
2353 // Remove the wildcards.
2354 String rootDomainName = domainName.substring(2);
2355 String rootCertificateCommonName = certificateCommonName.substring(2);
2357 // Check if one name ends with the contents of the other. If so, there will be overlap in the their wildcard subdomains.
2358 if (rootDomainName.endsWith(rootCertificateCommonName) || rootCertificateCommonName.endsWith(rootDomainName)) {
2359 domainNamesMatch = true;
2364 return domainNamesMatch;