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 defaultFontSizeTextView = domainSettingsView.findViewById(R.id.default_font_size_textview);
140 EditText customFontSizeEditText = domainSettingsView.findViewById(R.id.custom_font_size_edittext);
141 ImageView swipeToRefreshImageView = domainSettingsView.findViewById(R.id.swipe_to_refresh_imageview);
142 Spinner swipeToRefreshSpinner = domainSettingsView.findViewById(R.id.swipe_to_refresh_spinner);
143 TextView swipeToRefreshTextView = domainSettingsView.findViewById(R.id.swipe_to_refresh_textview);
144 ImageView nightModeImageView = domainSettingsView.findViewById(R.id.night_mode_imageview);
145 Spinner nightModeSpinner = domainSettingsView.findViewById(R.id.night_mode_spinner);
146 TextView nightModeTextView = domainSettingsView.findViewById(R.id.night_mode_textview);
147 ImageView wideViewportImageView = domainSettingsView.findViewById(R.id.wide_viewport_imageview);
148 Spinner wideViewportSpinner = domainSettingsView.findViewById(R.id.wide_viewport_spinner);
149 TextView wideViewportTextView = domainSettingsView.findViewById(R.id.wide_viewport_textview);
150 ImageView displayWebpageImagesImageView = domainSettingsView.findViewById(R.id.display_webpage_images_imageview);
151 Spinner displayWebpageImagesSpinner = domainSettingsView.findViewById(R.id.display_webpage_images_spinner);
152 TextView displayImagesTextView = domainSettingsView.findViewById(R.id.display_webpage_images_textview);
153 ImageView pinnedSslCertificateImageView = domainSettingsView.findViewById(R.id.pinned_ssl_certificate_imageview);
154 Switch pinnedSslCertificateSwitch = domainSettingsView.findViewById(R.id.pinned_ssl_certificate_switch);
155 CardView savedSslCardView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_cardview);
156 LinearLayout savedSslCertificateLinearLayout = domainSettingsView.findViewById(R.id.saved_ssl_certificate_linearlayout);
157 RadioButton savedSslCertificateRadioButton = domainSettingsView.findViewById(R.id.saved_ssl_certificate_radiobutton);
158 TextView savedSslIssuedToCNameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_to_cname);
159 TextView savedSslIssuedToONameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_to_oname);
160 TextView savedSslIssuedToUNameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_to_uname);
161 TextView savedSslIssuedByCNameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_by_cname);
162 TextView savedSslIssuedByONameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_by_oname);
163 TextView savedSslIssuedByUNameTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_by_uname);
164 TextView savedSslStartDateTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_start_date);
165 TextView savedSslEndDateTextView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_end_date);
166 CardView currentSslCardView = domainSettingsView.findViewById(R.id.current_website_certificate_cardview);
167 LinearLayout currentWebsiteCertificateLinearLayout = domainSettingsView.findViewById(R.id.current_website_certificate_linearlayout);
168 RadioButton currentWebsiteCertificateRadioButton = domainSettingsView.findViewById(R.id.current_website_certificate_radiobutton);
169 TextView currentSslIssuedToCNameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_to_cname);
170 TextView currentSslIssuedToONameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_to_oname);
171 TextView currentSslIssuedToUNameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_to_uname);
172 TextView currentSslIssuedByCNameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_by_cname);
173 TextView currentSslIssuedByONameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_by_oname);
174 TextView currentSslIssuedByUNameTextView = domainSettingsView.findViewById(R.id.current_website_certificate_issued_by_uname);
175 TextView currentSslStartDateTextView = domainSettingsView.findViewById(R.id.current_website_certificate_start_date);
176 TextView currentSslEndDateTextView = domainSettingsView.findViewById(R.id.current_website_certificate_end_date);
177 TextView noCurrentWebsiteCertificateTextView = domainSettingsView.findViewById(R.id.no_current_website_certificate);
178 ImageView pinnedIpAddressesImageView = domainSettingsView.findViewById(R.id.pinned_ip_addresses_imageview);
179 Switch pinnedIpAddressesSwitch = domainSettingsView.findViewById(R.id.pinned_ip_addresses_switch);
180 CardView savedIpAddressesCardView = domainSettingsView.findViewById(R.id.saved_ip_addresses_cardview);
181 LinearLayout savedIpAddressesLinearLayout = domainSettingsView.findViewById(R.id.saved_ip_addresses_linearlayout);
182 RadioButton savedIpAddressesRadioButton = domainSettingsView.findViewById(R.id.saved_ip_addresses_radiobutton);
183 TextView savedIpAddressesTextView = domainSettingsView.findViewById(R.id.saved_ip_addresses_textview);
184 CardView currentIpAddressesCardView = domainSettingsView.findViewById(R.id.current_ip_addresses_cardview);
185 LinearLayout currentIpAddressesLinearLayout = domainSettingsView.findViewById(R.id.current_ip_addresses_linearlayout);
186 RadioButton currentIpAddressesRadioButton = domainSettingsView.findViewById(R.id.current_ip_addresses_radiobutton);
187 TextView currentIpAddressesTextView = domainSettingsView.findViewById(R.id.current_ip_addresses_textview);
189 // Setup the pinned labels.
190 String cNameLabel = getString(R.string.common_name) + " ";
191 String oNameLabel = getString(R.string.organization) + " ";
192 String uNameLabel = getString(R.string.organizational_unit) + " ";
193 String startDateLabel = getString(R.string.start_date) + " ";
194 String endDateLabel = getString(R.string.end_date) + " ";
196 // Initialize the database handler. The `0` specifies the database version, but that is ignored and set instead using a constant in `DomainsDatabaseHelper`.
197 DomainsDatabaseHelper domainsDatabaseHelper = new DomainsDatabaseHelper(context, null, null, 0);
199 // Get the database cursor for this ID and move it to the first row.
200 Cursor domainCursor = domainsDatabaseHelper.getCursorForId(databaseId);
201 domainCursor.moveToFirst();
203 // Save the cursor entries as variables.
204 String domainNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.DOMAIN_NAME));
205 int javaScriptInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_JAVASCRIPT));
206 int firstPartyCookiesInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FIRST_PARTY_COOKIES));
207 int thirdPartyCookiesInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_THIRD_PARTY_COOKIES));
208 int domStorageInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_DOM_STORAGE));
209 int formDataInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FORM_DATA)); // Form data can be remove once the minimum API >= 26.
210 int easyListInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_EASYLIST));
211 int easyPrivacyInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_EASYPRIVACY));
212 int fanboysAnnoyanceListInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FANBOYS_ANNOYANCE_LIST));
213 int fanboysSocialBlockingListInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FANBOYS_SOCIAL_BLOCKING_LIST));
214 int ultraListInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ULTRALIST));
215 int ultraPrivacyInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_ULTRAPRIVACY));
216 int blockAllThirdPartyRequestsInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.BLOCK_ALL_THIRD_PARTY_REQUESTS));
217 String currentUserAgentName = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.USER_AGENT));
218 int fontSizeInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.FONT_SIZE));
219 int swipeToRefreshInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.SWIPE_TO_REFRESH));
220 int nightModeInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.NIGHT_MODE));
221 int wideViewportInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.WIDE_VIEWPORT));
222 int displayImagesInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.DISPLAY_IMAGES));
223 int pinnedSslCertificateInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.PINNED_SSL_CERTIFICATE));
224 String savedSslIssuedToCNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_TO_COMMON_NAME));
225 String savedSslIssuedToONameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_TO_ORGANIZATION));
226 String savedSslIssuedToUNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_TO_ORGANIZATIONAL_UNIT));
227 String savedSslIssuedByCNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_BY_COMMON_NAME));
228 String savedSslIssuedByONameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_BY_ORGANIZATION));
229 String savedSslIssuedByUNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_BY_ORGANIZATIONAL_UNIT));
230 int pinnedIpAddressesInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.PINNED_IP_ADDRESSES));
231 String savedIpAddresses = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.IP_ADDRESSES));
233 // Initialize the saved SSL certificate date variables.
234 Date savedSslStartDate = null;
235 Date savedSslEndDate = null;
237 // Only get the saved SSL certificate dates from the cursor if they are not set to `0`.
238 if (domainCursor.getLong(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_START_DATE)) != 0) {
239 savedSslStartDate = new Date(domainCursor.getLong(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_START_DATE)));
242 if (domainCursor.getLong(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_END_DATE)) != 0) {
243 savedSslEndDate = new Date(domainCursor.getLong(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_END_DATE)));
246 // Create array adapters for the spinners.
247 ArrayAdapter<CharSequence> translatedUserAgentArrayAdapter = ArrayAdapter.createFromResource(context, R.array.translated_domain_settings_user_agent_names, R.layout.spinner_item);
248 ArrayAdapter<CharSequence> fontSizeArrayAdapter = ArrayAdapter.createFromResource(context, R.array.font_size_array, 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 // Display the font size settings.
765 if (fontSizeInt == 0) { // `0` is the code for system default font size.
766 // Set the font size to the system default
767 fontSizeSpinner.setSelection(0);
769 // Show the default font size text view.
770 defaultFontSizeTextView.setVisibility(View.VISIBLE);
772 // Hide the custom font size edit text.
773 customFontSizeEditText.setVisibility(View.GONE);
775 // Set the default font size as the text of the custom font size edit text. This way, if the user switches to custom it will already be populated.
776 customFontSizeEditText.setText(defaultFontSizeString);
777 } else { // A custom font size is selected.
778 // Set the spinner to the custom font size.
779 fontSizeSpinner.setSelection(1);
781 // Hide the default font size text view.
782 defaultFontSizeTextView.setVisibility(View.GONE);
784 // Show the custom font size edit text.
785 customFontSizeEditText.setVisibility(View.GONE);
787 // Set the custom font size.
788 customFontSizeEditText.setText(String.valueOf(fontSizeInt));
791 // Initialize the default font size percentage string.
792 String defaultFontSizePercentageString = defaultFontSizeString + "%";
794 // Set the default font size text in the text view.
795 defaultFontSizeTextView.setText(defaultFontSizePercentageString);
797 // Open the font size spinner when the text view is clicked.
798 defaultFontSizeTextView.setOnClickListener((View v) -> {
799 // Open the user agent spinner.
800 fontSizeSpinner.performClick();
803 // Display the swipe to refresh selection in the spinner.
804 swipeToRefreshSpinner.setSelection(swipeToRefreshInt);
806 // Set the swipe to refresh text.
807 if (defaultSwipeToRefresh) {
808 swipeToRefreshTextView.setText(swipeToRefreshArrayAdapter.getItem(DomainsDatabaseHelper.ENABLED));
810 swipeToRefreshTextView.setText(swipeToRefreshArrayAdapter.getItem(DomainsDatabaseHelper.DISABLED));
813 // 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.
814 switch (swipeToRefreshInt) {
815 case DomainsDatabaseHelper.SYSTEM_DEFAULT:
816 if (defaultSwipeToRefresh) { // Swipe to refresh is enabled by default.
817 // Set the icon according to the theme.
819 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_enabled_dark));
821 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_enabled_light));
823 } else { // Swipe to refresh is disabled by default
824 // Set the icon according to the theme.
826 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_disabled_dark));
828 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_disabled_light));
832 // Show the swipe to refresh TextView.
833 swipeToRefreshTextView.setVisibility(View.VISIBLE);
836 case DomainsDatabaseHelper.ENABLED:
837 // Set the icon according to the theme.
839 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_enabled_dark));
841 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_enabled_light));
844 // Hide the swipe to refresh TextView.`
845 swipeToRefreshTextView.setVisibility(View.GONE);
848 case DomainsDatabaseHelper.DISABLED:
849 // Set the icon according to the theme.
851 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_disabled_dark));
853 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_disabled_light));
856 // Hide the swipe to refresh TextView.
857 swipeToRefreshTextView.setVisibility(View.GONE);
860 // Open the swipe to refresh spinner when the TextView is clicked.
861 swipeToRefreshTextView.setOnClickListener((View v) -> {
862 // Open the swipe to refresh spinner.
863 swipeToRefreshSpinner.performClick();
866 // Display the night mode in the spinner.
867 nightModeSpinner.setSelection(nightModeInt);
869 // Set the default night mode text.
870 if (defaultNightMode) {
871 nightModeTextView.setText(nightModeArrayAdapter.getItem(DomainsDatabaseHelper.ENABLED));
873 nightModeTextView.setText(nightModeArrayAdapter.getItem(DomainsDatabaseHelper.DISABLED));
876 // 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.
877 switch (nightModeInt) {
878 case DomainsDatabaseHelper.SYSTEM_DEFAULT:
879 if (defaultNightMode) { // Night mode enabled by default.
880 // Set the icon according to the theme.
882 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_dark));
884 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_light));
886 } else { // Night mode disabled by default.
887 // Set the icon according to the theme.
889 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_dark));
891 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_light));
895 // Show night mode TextView.
896 nightModeTextView.setVisibility(View.VISIBLE);
899 case DomainsDatabaseHelper.ENABLED:
900 // Set the icon according to the theme.
902 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_dark));
904 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_light));
907 // Hide the night mode TextView.
908 nightModeTextView.setVisibility(View.GONE);
911 case DomainsDatabaseHelper.DISABLED:
912 // Set the icon according to the theme.
914 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_dark));
916 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_light));
919 // Hide the night mode TextView.
920 nightModeTextView.setVisibility(View.GONE);
924 // Open the night mode spinner when the TextView is clicked.
925 nightModeTextView.setOnClickListener((View v) -> {
926 // Open the night mode spinner.
927 nightModeSpinner.performClick();
930 // Display the wide viewport in the spinner.
931 wideViewportSpinner.setSelection(wideViewportInt);
933 // Set the default wide viewport text.
934 if (defaultWideViewport) {
935 wideViewportTextView.setText(wideViewportArrayAdapter.getItem(DomainsDatabaseHelper.ENABLED));
937 wideViewportTextView.setText(wideViewportArrayAdapter.getItem(DomainsDatabaseHelper.DISABLED));
940 // 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.
941 switch (wideViewportInt) {
942 case DomainsDatabaseHelper.SYSTEM_DEFAULT:
943 if (defaultWideViewport) { // Wide viewport enabled by default.
944 // Set the icon according to the theme.
946 wideViewportImageView.setImageDrawable(resources.getDrawable(R.drawable.wide_viewport_enabled_dark));
948 wideViewportImageView.setImageDrawable(resources.getDrawable(R.drawable.wide_viewport_enabled_light));
950 } else { // Wide viewport disabled by default.
952 wideViewportImageView.setImageDrawable(resources.getDrawable(R.drawable.wide_viewport_disabled_dark));
954 wideViewportImageView.setImageDrawable(resources.getDrawable(R.drawable.wide_viewport_disabled_light));
958 // Show the wide viewport text view.
959 wideViewportTextView.setVisibility(View.VISIBLE);
962 case DomainsDatabaseHelper.ENABLED:
963 // Set the icon according to the theme.
965 wideViewportImageView.setImageDrawable(resources.getDrawable(R.drawable.wide_viewport_enabled_dark));
967 wideViewportImageView.setImageDrawable(resources.getDrawable(R.drawable.wide_viewport_enabled_light));
970 // Hide the wide viewport text view.
971 wideViewportTextView.setVisibility(View.GONE);
974 case DomainsDatabaseHelper.DISABLED:
975 // Set the icon according to the theme.
977 wideViewportImageView.setImageDrawable(resources.getDrawable(R.drawable.wide_viewport_disabled_dark));
979 wideViewportImageView.setImageDrawable(resources.getDrawable(R.drawable.wide_viewport_disabled_light));
982 // Hide the wide viewport text view.
983 wideViewportTextView.setVisibility(View.GONE);
987 // Open the wide viewport spinner when the text view is clicked.
988 wideViewportTextView.setOnClickListener((View view) -> {
989 // Open the wide viewport spinner.
990 wideViewportSpinner.performClick();
993 // Display the website images mode in the spinner.
994 displayWebpageImagesSpinner.setSelection(displayImagesInt);
996 // Set the default display images text.
997 if (defaultDisplayWebpageImages) {
998 displayImagesTextView.setText(displayImagesArrayAdapter.getItem(DomainsDatabaseHelper.ENABLED));
1000 displayImagesTextView.setText(displayImagesArrayAdapter.getItem(DomainsDatabaseHelper.DISABLED));
1003 // 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.
1004 switch (displayImagesInt) {
1005 case DomainsDatabaseHelper.SYSTEM_DEFAULT:
1006 if (defaultDisplayWebpageImages) { // Display webpage images enabled by default.
1007 // Set the icon according to the theme.
1009 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_dark));
1011 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_light));
1013 } else { // Display webpage images disabled by default.
1014 // Set the icon according to the theme.
1016 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_dark));
1018 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_light));
1022 // Show the display images text view.
1023 displayImagesTextView.setVisibility(View.VISIBLE);
1026 case DomainsDatabaseHelper.ENABLED:
1027 // Set the icon according to the theme.
1029 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_dark));
1031 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_light));
1034 // Hide the display images text view.
1035 displayImagesTextView.setVisibility(View.GONE);
1038 case DomainsDatabaseHelper.DISABLED:
1039 // Set the icon according to the theme.
1041 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_dark));
1043 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_light));
1046 // Hide the display images text view.
1047 displayImagesTextView.setVisibility(View.GONE);
1051 // Open the display images spinner when the text view is clicked.
1052 displayImagesTextView.setOnClickListener((View view) -> {
1053 // Open the user agent spinner.
1054 displayWebpageImagesSpinner.performClick();
1057 // Set the pinned SSL certificate icon.
1058 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.
1059 // Check the switch.
1060 pinnedSslCertificateSwitch.setChecked(true);
1062 // Set the icon according to the theme.
1064 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_dark));
1066 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_light));
1068 } else { // Pinned SSL certificate is disabled.
1069 // Uncheck the switch.
1070 pinnedSslCertificateSwitch.setChecked(false);
1072 // Set the icon according to the theme.
1074 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_dark));
1076 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_light));
1080 // Store the current date.
1081 Date currentDate = Calendar.getInstance().getTime();
1083 // Setup the string builders to display the general certificate information in blue. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
1084 savedSslIssuedToONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), savedSslIssuedToONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1085 savedSslIssuedToUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), savedSslIssuedToUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1086 savedSslIssuedByCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), savedSslIssuedByCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1087 savedSslIssuedByONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), savedSslIssuedByONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1088 savedSslIssuedByUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), savedSslIssuedByUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1090 // Check the certificate Common Name against the domain name.
1091 boolean savedSslCommonNameMatchesDomainName = checkDomainNameAgainstCertificate(domainNameString, savedSslIssuedToCNameString);
1093 // Format the issued to Common Name color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
1094 if (savedSslCommonNameMatchesDomainName) {
1095 savedSslIssuedToCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), savedSslIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1097 savedSslIssuedToCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), savedSslIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1100 // Format the start date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
1101 if ((savedSslStartDate != null) && savedSslStartDate.after(currentDate)) { // The certificate start date is in the future.
1102 savedSslStartDateStringBuilder.setSpan(redColorSpan, startDateLabel.length(), savedSslStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1103 } else { // The certificate start date is in the past.
1104 savedSslStartDateStringBuilder.setSpan(blueColorSpan, startDateLabel.length(), savedSslStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1107 // Format the end date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
1108 if ((savedSslEndDate != null) && savedSslEndDate.before(currentDate)) { // The certificate end date is in the past.
1109 savedSslEndDateStringBuilder.setSpan(redColorSpan, endDateLabel.length(), savedSslEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1110 } else { // The certificate end date is in the future.
1111 savedSslEndDateStringBuilder.setSpan(blueColorSpan, endDateLabel.length(), savedSslEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1114 // Display the saved website SSL certificate strings.
1115 savedSslIssuedToCNameTextView.setText(savedSslIssuedToCNameStringBuilder);
1116 savedSslIssuedToONameTextView.setText(savedSslIssuedToONameStringBuilder);
1117 savedSslIssuedToUNameTextView.setText(savedSslIssuedToUNameStringBuilder);
1118 savedSslIssuedByCNameTextView.setText(savedSslIssuedByCNameStringBuilder);
1119 savedSslIssuedByONameTextView.setText(savedSslIssuedByONameStringBuilder);
1120 savedSslIssuedByUNameTextView.setText(savedSslIssuedByUNameStringBuilder);
1121 savedSslStartDateTextView.setText(savedSslStartDateStringBuilder);
1122 savedSslEndDateTextView.setText(savedSslEndDateStringBuilder);
1124 // Populate the current website SSL certificate if there is one.
1125 if (DomainsActivity.sslIssuedToCName != null) {
1126 // Get dates from the raw long values.
1127 Date currentSslStartDate = new Date(DomainsActivity.sslStartDateLong);
1128 Date currentSslEndDate = new Date(DomainsActivity.sslEndDateLong);
1130 // Create a spannable string builder for each text view that needs multiple colors of text.
1131 SpannableStringBuilder currentSslIssuedToCNameStringBuilder = new SpannableStringBuilder(cNameLabel + DomainsActivity.sslIssuedToCName);
1132 SpannableStringBuilder currentSslIssuedToONameStringBuilder = new SpannableStringBuilder(oNameLabel + DomainsActivity.sslIssuedToOName);
1133 SpannableStringBuilder currentSslIssuedToUNameStringBuilder = new SpannableStringBuilder(uNameLabel + DomainsActivity.sslIssuedToUName);
1134 SpannableStringBuilder currentSslIssuedByCNameStringBuilder = new SpannableStringBuilder(cNameLabel + DomainsActivity.sslIssuedByCName);
1135 SpannableStringBuilder currentSslIssuedByONameStringBuilder = new SpannableStringBuilder(oNameLabel + DomainsActivity.sslIssuedByOName);
1136 SpannableStringBuilder currentSslIssuedByUNameStringBuilder = new SpannableStringBuilder(uNameLabel + DomainsActivity.sslIssuedByUName);
1137 SpannableStringBuilder currentSslStartDateStringBuilder = new SpannableStringBuilder(startDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG)
1138 .format(currentSslStartDate));
1139 SpannableStringBuilder currentSslEndDateStringBuilder = new SpannableStringBuilder(endDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG)
1140 .format(currentSslEndDate));
1142 // Setup the string builders to display the general certificate information in blue. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
1143 currentSslIssuedToONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), currentSslIssuedToONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1144 currentSslIssuedToUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), currentSslIssuedToUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1145 currentSslIssuedByCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), currentSslIssuedByCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1146 currentSslIssuedByONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), currentSslIssuedByONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1147 currentSslIssuedByUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), currentSslIssuedByUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1149 // Check the certificate Common Name against the domain name.
1150 boolean currentSslCommonNameMatchesDomainName = checkDomainNameAgainstCertificate(domainNameString, DomainsActivity.sslIssuedToCName);
1152 // Format the issued to Common Name color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
1153 if (currentSslCommonNameMatchesDomainName) {
1154 currentSslIssuedToCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), currentSslIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1156 currentSslIssuedToCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), currentSslIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1159 // Format the start date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
1160 if (currentSslStartDate.after(currentDate)) { // The certificate start date is in the future.
1161 currentSslStartDateStringBuilder.setSpan(redColorSpan, startDateLabel.length(), currentSslStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1162 } else { // The certificate start date is in the past.
1163 currentSslStartDateStringBuilder.setSpan(blueColorSpan, startDateLabel.length(), currentSslStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1166 // Format the end date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
1167 if (currentSslEndDate.before(currentDate)) { // The certificate end date is in the past.
1168 currentSslEndDateStringBuilder.setSpan(redColorSpan, endDateLabel.length(), currentSslEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1169 } else { // The certificate end date is in the future.
1170 currentSslEndDateStringBuilder.setSpan(blueColorSpan, endDateLabel.length(), currentSslEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
1173 // Display the current website SSL certificate strings.
1174 currentSslIssuedToCNameTextView.setText(currentSslIssuedToCNameStringBuilder);
1175 currentSslIssuedToONameTextView.setText(currentSslIssuedToONameStringBuilder);
1176 currentSslIssuedToUNameTextView.setText(currentSslIssuedToUNameStringBuilder);
1177 currentSslIssuedByCNameTextView.setText(currentSslIssuedByCNameStringBuilder);
1178 currentSslIssuedByONameTextView.setText(currentSslIssuedByONameStringBuilder);
1179 currentSslIssuedByUNameTextView.setText(currentSslIssuedByUNameStringBuilder);
1180 currentSslStartDateTextView.setText(currentSslStartDateStringBuilder);
1181 currentSslEndDateTextView.setText(currentSslEndDateStringBuilder);
1184 // Set the initial display status of the SSL certificates card views.
1185 if (pinnedSslCertificateSwitch.isChecked()) { // An SSL certificate is pinned.
1186 // Set the visibility of the saved SSL certificate.
1187 if (savedSslIssuedToCNameString == null) {
1188 savedSslCardView.setVisibility(View.GONE);
1190 savedSslCardView.setVisibility(View.VISIBLE);
1193 // Set the visibility of the current website SSL certificate.
1194 if (DomainsActivity.sslIssuedToCName == null) { // There is no current SSL certificate.
1195 // Hide the SSL certificate.
1196 currentSslCardView.setVisibility(View.GONE);
1198 // Show the instruction.
1199 noCurrentWebsiteCertificateTextView.setVisibility(View.VISIBLE);
1200 } else { // There is a current SSL certificate.
1201 // Show the SSL certificate.
1202 currentSslCardView.setVisibility(View.VISIBLE);
1204 // Hide the instruction.
1205 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
1208 // Set the status of the radio buttons and the card view backgrounds.
1209 if (savedSslCardView.getVisibility() == View.VISIBLE) { // The saved SSL certificate is displayed.
1210 // Check the saved SSL certificate radio button.
1211 savedSslCertificateRadioButton.setChecked(true);
1213 // Uncheck the current website SSL certificate radio button.
1214 currentWebsiteCertificateRadioButton.setChecked(false);
1216 // Darken the background of the current website SSL certificate linear layout according to the theme.
1218 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1220 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1222 } else if (currentSslCardView.getVisibility() == View.VISIBLE) { // The saved SSL certificate is hidden but the current website SSL certificate is visible.
1223 // Check the current website SSL certificate radio button.
1224 currentWebsiteCertificateRadioButton.setChecked(true);
1226 // Uncheck the saved SSL certificate radio button.
1227 savedSslCertificateRadioButton.setChecked(false);
1228 } else { // Neither SSL certificate is visible.
1229 // Uncheck both radio buttons.
1230 savedSslCertificateRadioButton.setChecked(false);
1231 currentWebsiteCertificateRadioButton.setChecked(false);
1233 } else { // An SSL certificate is not pinned.
1234 // Hide the SSl certificates and instructions.
1235 savedSslCardView.setVisibility(View.GONE);
1236 currentSslCardView.setVisibility(View.GONE);
1237 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
1239 // Uncheck the radio buttons.
1240 savedSslCertificateRadioButton.setChecked(false);
1241 currentWebsiteCertificateRadioButton.setChecked(false);
1244 // Set the pinned IP addresses icon.
1245 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.
1246 // Check the switch.
1247 pinnedIpAddressesSwitch.setChecked(true);
1249 // Set the icon according to the theme.
1251 pinnedIpAddressesImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_dark));
1253 pinnedIpAddressesImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_light));
1255 } else { // Pinned IP Addresses is disabled.
1256 // Uncheck the switch.
1257 pinnedIpAddressesSwitch.setChecked(false);
1259 // Set the icon according to the theme.
1261 pinnedIpAddressesImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_dark));
1263 pinnedIpAddressesImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_light));
1267 // Populate the saved and current IP addresses.
1268 savedIpAddressesTextView.setText(savedIpAddresses);
1269 currentIpAddressesTextView.setText(DomainsActivity.currentIpAddresses);
1271 // Set the initial display status of the IP addresses card views.
1272 if (pinnedIpAddressesSwitch.isChecked()) { // IP addresses are pinned.
1273 // Set the visibility of the saved IP addresses.
1274 if (savedIpAddresses == null) { // There are no saved IP addresses.
1275 savedIpAddressesCardView.setVisibility(View.GONE);
1276 } else { // There are saved IP addresses.
1277 savedIpAddressesCardView.setVisibility(View.VISIBLE);
1280 // Set the visibility of the current IP addresses.
1281 currentIpAddressesCardView.setVisibility(View.VISIBLE);
1283 // Set the status of the radio buttons and the card view backgrounds.
1284 if (savedIpAddressesCardView.getVisibility() == View.VISIBLE) { // The saved IP addresses are displayed.
1285 // Check the saved IP addresses radio button.
1286 savedIpAddressesRadioButton.setChecked(true);
1288 // Uncheck the current IP addresses radio button.
1289 currentIpAddressesRadioButton.setChecked(false);
1291 // Darken the background of the current IP addresses linear layout according to the theme.
1293 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
1295 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
1297 } else { // The saved IP addresses are hidden.
1298 // Check the current IP addresses radio button.
1299 currentIpAddressesRadioButton.setChecked(true);
1301 // Uncheck the saved IP addresses radio button.
1302 savedIpAddressesRadioButton.setChecked(false);
1304 } else { // IP addresses are not pinned.
1305 // Hide the IP addresses card views.
1306 savedIpAddressesCardView.setVisibility(View.GONE);
1307 currentIpAddressesCardView.setVisibility(View.GONE);
1309 // Uncheck the radio buttons.
1310 savedIpAddressesRadioButton.setChecked(false);
1311 currentIpAddressesRadioButton.setChecked(false);
1315 // Set the JavaScript switch listener.
1316 javaScriptSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1317 if (isChecked) { // JavaScript is enabled.
1318 // Update the JavaScript icon.
1319 javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.javascript_enabled));
1321 // Enable the DOM storage `Switch`.
1322 domStorageSwitch.setEnabled(true);
1324 // Update the DOM storage icon.
1325 if (domStorageSwitch.isChecked()) { // DOM storage is enabled.
1326 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_enabled));
1327 } else { // DOM storage is disabled.
1328 // Set the icon according to the theme.
1330 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_dark));
1332 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_light));
1335 } else { // JavaScript is disabled.
1336 // Update the JavaScript icon.
1337 javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.privacy_mode));
1339 // Disable the DOM storage `Switch`.
1340 domStorageSwitch.setEnabled(false);
1342 // Set the DOM storage icon according to the theme.
1344 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_dark));
1346 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_light));
1351 // Set the first-party cookies switch listener.
1352 firstPartyCookiesSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1353 if (isChecked) { // First-party cookies are enabled.
1354 // Update the first-party cookies icon.
1355 firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_enabled));
1357 // Enable the third-party cookies switch.
1358 thirdPartyCookiesSwitch.setEnabled(true);
1360 // Update the third-party cookies icon.
1361 if (thirdPartyCookiesSwitch.isChecked()) { // Third-party cookies are enabled.
1362 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_warning));
1363 } else { // Third-party cookies are disabled.
1364 // Set the third-party cookies icon according to the theme.
1366 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_dark));
1368 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_light));
1371 } else { // First-party cookies are disabled.
1372 // Update the first-party cookies icon according to the theme.
1374 firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_dark));
1376 firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_light));
1379 // Disable the third-party cookies switch.
1380 thirdPartyCookiesSwitch.setEnabled(false);
1382 // Set the third-party cookies icon according to the theme.
1384 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_ghosted_dark));
1386 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_ghosted_light));
1391 // Set the third-party cookies switch listener.
1392 thirdPartyCookiesSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1395 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_warning));
1397 // Update the third-party cookies icon according to the theme.
1399 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_dark));
1401 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_light));
1406 // Set the DOM Storage switch listener.
1407 domStorageSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1410 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_enabled));
1412 // Set the icon according to the theme.
1414 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_dark));
1416 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_light));
1421 // Set the form data switch listener. It can be removed once the minimum API >= 26.
1422 if (Build.VERSION.SDK_INT < 26) {
1423 formDataSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1426 formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_enabled));
1428 // Set the icon according to the theme.
1430 formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_disabled_dark));
1432 formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_disabled_light));
1438 // Set the EasyList switch listener.
1439 easyListSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1441 if (isChecked) { // EasyList is on.
1442 // Set the icon according to the theme.
1444 easyListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_enabled_dark));
1446 easyListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_enabled_light));
1448 } else { // EasyList is off.
1449 // Set the icon according to the theme.
1451 easyListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_disabled_dark));
1453 easyListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_disabled_light));
1458 // Set the EasyPrivacy switch listener.
1459 easyPrivacySwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1461 if (isChecked) { // EasyPrivacy is on.
1462 // Set the icon according to the theme.
1464 easyPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_enabled_dark));
1466 easyPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_enabled_light));
1468 } else { // EasyPrivacy is off.
1469 // Set the icon according to the theme.
1471 easyPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_disabled_dark));
1473 easyPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_disabled_light));
1478 // Set the Fanboy's Annoyance List switch listener.
1479 fanboysAnnoyanceListSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1480 // Update the icon and Fanboy's Social Blocking List.
1481 if (isChecked) { // Fanboy's Annoyance List is on.
1482 // Set the icon according to the theme.
1484 fanboysAnnoyanceListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_dark));
1486 fanboysAnnoyanceListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_light));
1489 // Disable the Fanboy's Social Blocking List switch.
1490 fanboysSocialBlockingListSwitch.setEnabled(false);
1492 // Update the Fanboy's Social Blocking List icon according to the theme.
1494 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_ghosted_dark));
1496 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_ghosted_light));
1498 } else { // Fanboy's Annoyance List is off.
1499 // Set the icon according to the theme.
1501 fanboysAnnoyanceListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_dark));
1503 fanboysAnnoyanceListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_light));
1506 // Enable the Fanboy's Social Blocking List switch.
1507 fanboysSocialBlockingListSwitch.setEnabled(true);
1509 // Update the Fanboy's Social Blocking List icon.
1510 if (fanboysSocialBlockingListSwitch.isChecked()) { // Fanboy's Social Blocking List is on.
1511 // Update the icon according to the theme.
1513 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_dark));
1515 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_light));
1517 } else { // Fanboy's Social Blocking List is off.
1518 // Update the icon according to the theme.
1520 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_dark));
1522 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_light));
1529 // Set the Fanboy's Social Blocking List switch listener.
1530 fanboysSocialBlockingListSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1532 if (isChecked) { // Fanboy's Social Blocking List is on.
1533 // Set the icon according to the theme.
1535 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_dark));
1537 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_enabled_light));
1539 } else { // Fanboy's Social Blocking List is off.
1540 // Set the icon according to the theme.
1542 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_dark));
1544 fanboysSocialBlockingListImageView.setImageDrawable(resources.getDrawable(R.drawable.social_media_disabled_light));
1549 // Set the UltraList switch listener.
1550 ultraListSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1552 if (isChecked) { // UltraList is on.
1553 // Set the icon according to the theme.
1555 ultraListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_enabled_dark));
1557 ultraListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_enabled_light));
1559 } else { // UltraList is off.
1560 // Set the icon according to the theme.
1562 ultraListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_disabled_dark));
1564 ultraListImageView.setImageDrawable(resources.getDrawable(R.drawable.block_ads_disabled_light));
1569 // Set the UltraPrivacy switch listener.
1570 ultraPrivacySwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1572 if (isChecked) { // UltraPrivacy is on.
1573 // Set the icon according to the theme.
1575 ultraPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_enabled_dark));
1577 ultraPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_enabled_light));
1579 } else { // UltraPrivacy is off.
1580 // Set the icon according to the theme.
1582 ultraPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_disabled_dark));
1584 ultraPrivacyImageView.setImageDrawable(resources.getDrawable(R.drawable.block_tracking_disabled_light));
1589 // Set the block all third-party requests switch listener.
1590 blockAllThirdPartyRequestsSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1592 if (isChecked) { // Blocking all third-party requests is on.
1593 // Set the icon according to the theme.
1595 blockAllThirdPartyRequestsImageView.setImageDrawable(resources.getDrawable(R.drawable.block_all_third_party_requests_enabled_dark));
1597 blockAllThirdPartyRequestsImageView.setImageDrawable(resources.getDrawable(R.drawable.block_all_third_party_requests_enabled_light));
1599 } else { // Blocking all third-party requests is off.
1600 // Set the icon according to the theme.
1602 blockAllThirdPartyRequestsImageView.setImageDrawable(resources.getDrawable(R.drawable.block_all_third_party_requests_disabled_dark));
1604 blockAllThirdPartyRequestsImageView.setImageDrawable(resources.getDrawable(R.drawable.block_all_third_party_requests_disabled_light));
1609 // Set the user agent spinner listener.
1610 userAgentSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1612 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1613 // Set the new user agent.
1615 case MainWebViewActivity.DOMAINS_SYSTEM_DEFAULT_USER_AGENT:
1616 // Show the user agent TextView.
1617 userAgentTextView.setVisibility(View.VISIBLE);
1619 // Hide the custom user agent EditText.
1620 customUserAgentEditText.setVisibility(View.GONE);
1622 // Set the user text.
1623 switch (defaultUserAgentArrayPosition) {
1624 case MainWebViewActivity.UNRECOGNIZED_USER_AGENT: // The default user agent name is not on the canonical list.
1625 // This is probably because it was set in an older version of Privacy Browser before the switch to persistent user agent names.
1626 userAgentTextView.setText(defaultUserAgentName);
1629 case MainWebViewActivity.SETTINGS_WEBVIEW_DEFAULT_USER_AGENT:
1630 // Display the `WebView` default user agent.
1631 userAgentTextView.setText(webViewDefaultUserAgentString);
1634 case MainWebViewActivity.SETTINGS_CUSTOM_USER_AGENT:
1635 // Display the custom user agent.
1636 userAgentTextView.setText(defaultCustomUserAgentString);
1640 // Get the user agent string from the user agent data array.
1641 userAgentTextView.setText(userAgentDataArray[defaultUserAgentArrayPosition]);
1645 case MainWebViewActivity.DOMAINS_WEBVIEW_DEFAULT_USER_AGENT:
1646 // Show the user agent TextView and set the text.
1647 userAgentTextView.setVisibility(View.VISIBLE);
1648 userAgentTextView.setText(webViewDefaultUserAgentString);
1650 // Hide the custom user agent EditTex.
1651 customUserAgentEditText.setVisibility(View.GONE);
1654 case MainWebViewActivity.DOMAINS_CUSTOM_USER_AGENT:
1655 // Hide the user agent TextView.
1656 userAgentTextView.setVisibility(View.GONE);
1658 // Show the custom user agent EditText and set the current user agent name as the text.
1659 customUserAgentEditText.setVisibility(View.VISIBLE);
1660 customUserAgentEditText.setText(currentUserAgentName);
1664 // 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.
1665 userAgentTextView.setVisibility(View.VISIBLE);
1666 userAgentTextView.setText(userAgentDataArray[position - 1]);
1668 // Hide `customUserAgentEditText`.
1669 customUserAgentEditText.setVisibility(View.GONE);
1674 public void onNothingSelected(AdapterView<?> parent) {
1679 // Set the font size spinner listener.
1680 fontSizeSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1682 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1683 // Update the font size display options.
1684 if (position == 0) { // The system default font size has been selected.
1685 // Show the default font size text view.
1686 defaultFontSizeTextView.setVisibility(View.VISIBLE);
1688 // Hide the custom font size edit text.
1689 customFontSizeEditText.setVisibility(View.GONE);
1690 } else { // A custom font size has been selected.
1691 // Hide the default font size text view.
1692 defaultFontSizeTextView.setVisibility(View.GONE);
1694 // Show the custom font size edit text.
1695 customFontSizeEditText.setVisibility(View.VISIBLE);
1700 public void onNothingSelected(AdapterView<?> parent) {
1705 // Set the swipe to refresh spinner listener.
1706 swipeToRefreshSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1708 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1709 // 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.
1711 case DomainsDatabaseHelper.SYSTEM_DEFAULT:
1712 if (defaultSwipeToRefresh) { // Swipe to refresh enabled by default.
1713 // Set the icon according to the theme.
1715 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_enabled_dark));
1717 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_enabled_light));
1719 } else { // Swipe to refresh disabled by default.
1720 // Set the icon according to the theme.
1722 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_disabled_dark));
1724 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_disabled_light));
1728 // Show the swipe to refresh TextView.
1729 swipeToRefreshTextView.setVisibility(View.VISIBLE);
1732 case DomainsDatabaseHelper.ENABLED:
1733 // Set the icon according to the theme.
1735 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_enabled_dark));
1737 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_enabled_light));
1740 // Hide the swipe to refresh TextView.
1741 swipeToRefreshTextView.setVisibility(View.GONE);
1744 case DomainsDatabaseHelper.DISABLED:
1745 // Set the icon according to the theme.
1747 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_disabled_dark));
1749 swipeToRefreshImageView.setImageDrawable(resources.getDrawable(R.drawable.refresh_disabled_light));
1752 // Hide the swipe to refresh TextView.
1753 swipeToRefreshTextView.setVisibility(View.GONE);
1758 public void onNothingSelected(AdapterView<?> parent) {
1763 // Set the night mode spinner listener.
1764 nightModeSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1766 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1767 // 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.
1769 case DomainsDatabaseHelper.SYSTEM_DEFAULT:
1770 if (defaultNightMode) { // Night mode enabled by default.
1771 // Set the icon according to the theme.
1773 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_dark));
1775 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_light));
1777 } else { // Night mode disabled by default.
1778 // Set the icon according to the theme.
1780 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_dark));
1782 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_light));
1786 // Show the night mode TextView.
1787 nightModeTextView.setVisibility(View.VISIBLE);
1790 case DomainsDatabaseHelper.ENABLED:
1791 // Set the icon according to the theme.
1793 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_dark));
1795 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_light));
1798 // Hide `nightModeTextView`.
1799 nightModeTextView.setVisibility(View.GONE);
1802 case DomainsDatabaseHelper.DISABLED:
1803 // Set the icon according to the theme.
1805 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_dark));
1807 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_light));
1810 // Hide `nightModeTextView`.
1811 nightModeTextView.setVisibility(View.GONE);
1815 // Create a boolean to store the current night mode setting.
1816 boolean currentNightModeEnabled = (position == DomainsDatabaseHelper.ENABLED) || ((position == DomainsDatabaseHelper.SYSTEM_DEFAULT) && defaultNightMode);
1818 // Disable the JavaScript switch if night mode is enabled.
1819 if (currentNightModeEnabled) {
1820 javaScriptSwitch.setEnabled(false);
1822 javaScriptSwitch.setEnabled(true);
1825 // Update the JavaScript icon.
1826 if ((javaScriptInt == 1) || currentNightModeEnabled) {
1827 javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.javascript_enabled));
1829 javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.privacy_mode));
1832 // Update the DOM storage status.
1833 if ((javaScriptInt == 1) || currentNightModeEnabled) { // JavaScript is enabled.
1834 // Enable the DOM storage `Switch`.
1835 domStorageSwitch.setEnabled(true);
1837 // Set the DOM storage status. Once the minimum API >= 21 a selector can be used as the tint mode instead of specifying different icons.
1838 if (domStorageInt == 1) { // Both JavaScript and DOM storage are enabled.
1839 domStorageSwitch.setChecked(true);
1840 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_enabled));
1841 } else { // JavaScript is enabled but DOM storage is disabled.
1842 // Set the DOM storage switch to off.
1843 domStorageSwitch.setChecked(false);
1845 // Set the icon according to the theme.
1847 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_dark));
1849 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_light));
1852 } else { // JavaScript is disabled.
1853 // Disable the DOM storage `Switch`.
1854 domStorageSwitch.setEnabled(false);
1856 // Set the checked status of DOM storage.
1857 if (domStorageInt == 1) { // DOM storage is enabled but JavaScript is disabled.
1858 domStorageSwitch.setChecked(true);
1859 } else { // Both JavaScript and DOM storage are disabled.
1860 domStorageSwitch.setChecked(false);
1863 // Set the icon according to the theme.
1865 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_dark));
1867 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_light));
1873 public void onNothingSelected(AdapterView<?> parent) {
1878 // Set the wide viewport spinner listener.
1879 wideViewportSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1881 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1882 // Update the icon and the visibility of the wide viewport text view.
1884 case DomainsDatabaseHelper.SYSTEM_DEFAULT:
1885 if (defaultWideViewport) { // Wide viewport is enabled by default.
1886 // Set the icon according to the theme.
1888 wideViewportImageView.setImageDrawable(resources.getDrawable(R.drawable.wide_viewport_enabled_dark));
1890 wideViewportImageView.setImageDrawable(resources.getDrawable(R.drawable.wide_viewport_enabled_light));
1892 } else { // Wide viewport is disabled by default.
1894 wideViewportImageView.setImageDrawable(resources.getDrawable(R.drawable.wide_viewport_disabled_dark));
1896 wideViewportImageView.setImageDrawable(resources.getDrawable(R.drawable.wide_viewport_disabled_light));
1900 // Show the wide viewport text view.
1901 wideViewportTextView.setVisibility(View.VISIBLE);
1904 case DomainsDatabaseHelper.ENABLED:
1905 // Set the icon according to the theme.
1907 wideViewportImageView.setImageDrawable(resources.getDrawable(R.drawable.wide_viewport_enabled_dark));
1909 wideViewportImageView.setImageDrawable(resources.getDrawable(R.drawable.wide_viewport_enabled_light));
1912 // Hide the wide viewport text view.
1913 wideViewportTextView.setVisibility(View.GONE);
1916 case DomainsDatabaseHelper.DISABLED:
1917 // Set the icon according to the theme.
1919 wideViewportImageView.setImageDrawable(resources.getDrawable(R.drawable.wide_viewport_disabled_dark));
1921 wideViewportImageView.setImageDrawable(resources.getDrawable(R.drawable.wide_viewport_disabled_light));
1924 // Hid ethe wide viewport text view.
1925 wideViewportTextView.setVisibility(View.GONE);
1931 public void onNothingSelected(AdapterView<?> parent) {
1936 // Set the display webpage images spinner listener.
1937 displayWebpageImagesSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1939 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1940 // Update the icon and the visibility of the display images text view.
1942 case DomainsDatabaseHelper.SYSTEM_DEFAULT:
1943 if (defaultDisplayWebpageImages) { // Display webpage images is enabled by default.
1944 // Set the icon according to the theme.
1946 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_dark));
1948 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_light));
1950 } else { // Display webpage images is disabled by default.
1951 // Set the icon according to the theme.
1953 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_dark));
1955 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_light));
1959 // Show the display images text view.
1960 displayImagesTextView.setVisibility(View.VISIBLE);
1963 case DomainsDatabaseHelper.ENABLED:
1964 // Set the icon according to the theme.
1966 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_dark));
1968 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_light));
1971 // Hide the display images text view.
1972 displayImagesTextView.setVisibility(View.GONE);
1975 case DomainsDatabaseHelper.DISABLED:
1976 // Set the icon according to the theme.
1978 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_dark));
1980 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_light));
1983 // Hide the display images text view.
1984 displayImagesTextView.setVisibility(View.GONE);
1990 public void onNothingSelected(AdapterView<?> parent) {
1995 // Set the pinned SSL certificate switch listener.
1996 pinnedSslCertificateSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
1998 if (isChecked) { // SSL certificate pinning is enabled.
1999 // Set the icon according to the theme.
2001 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_dark));
2003 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_light));
2006 // Update the visibility of the saved SSL certificate.
2007 if (savedSslIssuedToCNameString == null) {
2008 savedSslCardView.setVisibility(View.GONE);
2010 savedSslCardView.setVisibility(View.VISIBLE);
2013 // Update the visibility of the current website SSL certificate.
2014 if (DomainsActivity.sslIssuedToCName == null) {
2015 // Hide the SSL certificate.
2016 currentSslCardView.setVisibility(View.GONE);
2018 // Show the instruction.
2019 noCurrentWebsiteCertificateTextView.setVisibility(View.VISIBLE);
2021 // Show the SSL certificate.
2022 currentSslCardView.setVisibility(View.VISIBLE);
2024 // Hide the instruction.
2025 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
2028 // Set the status of the radio buttons.
2029 if (savedSslCardView.getVisibility() == View.VISIBLE) { // The saved SSL certificate is displayed.
2030 // Check the saved SSL certificate radio button.
2031 savedSslCertificateRadioButton.setChecked(true);
2033 // Uncheck the current website SSL certificate radio button.
2034 currentWebsiteCertificateRadioButton.setChecked(false);
2036 // Set the background of the saved SSL certificate linear layout to be transparent.
2037 savedSslCertificateLinearLayout.setBackgroundResource(R.color.transparent);
2039 // Darken the background of the current website SSL certificate linear layout according to the theme.
2041 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2043 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2046 // Scroll to the current website SSL certificate card.
2047 savedSslCardView.getParent().requestChildFocus(savedSslCardView, savedSslCardView);
2048 } else if (currentSslCardView.getVisibility() == View.VISIBLE) { // The saved SSL certificate is hidden but the current website SSL certificate is visible.
2049 // Check the current website SSL certificate radio button.
2050 currentWebsiteCertificateRadioButton.setChecked(true);
2052 // Uncheck the saved SSL certificate radio button.
2053 savedSslCertificateRadioButton.setChecked(false);
2055 // Set the background of the current website SSL certificate linear layout to be transparent.
2056 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.transparent);
2058 // Darken the background of the saved SSL certificate linear layout according to the theme.
2060 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2062 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2065 // Scroll to the current website SSL certificate card.
2066 currentSslCardView.getParent().requestChildFocus(currentSslCardView, currentSslCardView);
2067 } else { // Neither SSL certificate is visible.
2068 // Uncheck both radio buttons.
2069 savedSslCertificateRadioButton.setChecked(false);
2070 currentWebsiteCertificateRadioButton.setChecked(false);
2072 // Scroll to the current website SSL certificate card.
2073 noCurrentWebsiteCertificateTextView.getParent().requestChildFocus(noCurrentWebsiteCertificateTextView, noCurrentWebsiteCertificateTextView);
2075 } else { // SSL certificate pinning is disabled.
2076 // Set the icon according to the theme.
2078 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_dark));
2080 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_light));
2083 // Hide the SSl certificates and instructions.
2084 savedSslCardView.setVisibility(View.GONE);
2085 currentSslCardView.setVisibility(View.GONE);
2086 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
2088 // Uncheck the radio buttons.
2089 savedSslCertificateRadioButton.setChecked(false);
2090 currentWebsiteCertificateRadioButton.setChecked(false);
2094 savedSslCardView.setOnClickListener((View view) -> {
2095 // Check the saved SSL certificate radio button.
2096 savedSslCertificateRadioButton.setChecked(true);
2098 // Uncheck the current website SSL certificate radio button.
2099 currentWebsiteCertificateRadioButton.setChecked(false);
2101 // Set the background of the saved SSL certificate linear layout to be transparent.
2102 savedSslCertificateLinearLayout.setBackgroundResource(R.color.transparent);
2104 // Darken the background of the current website SSL certificate linear layout according to the theme.
2106 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2108 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2112 savedSslCertificateRadioButton.setOnClickListener((View view) -> {
2113 // Check the saved SSL certificate radio button.
2114 savedSslCertificateRadioButton.setChecked(true);
2116 // Uncheck the current website SSL certificate radio button.
2117 currentWebsiteCertificateRadioButton.setChecked(false);
2119 // Set the background of the saved SSL certificate linear layout to be transparent.
2120 savedSslCertificateLinearLayout.setBackgroundResource(R.color.transparent);
2122 // Darken the background of the current website SSL certificate linear layout according to the theme.
2124 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2126 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2130 currentSslCardView.setOnClickListener((View view) -> {
2131 // Check the current website SSL certificate radio button.
2132 currentWebsiteCertificateRadioButton.setChecked(true);
2134 // Uncheck the saved SSL certificate radio button.
2135 savedSslCertificateRadioButton.setChecked(false);
2137 // Set the background of the current website SSL certificate linear layout to be transparent.
2138 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.transparent);
2140 // Darken the background of the saved SSL certificate linear layout according to the theme.
2142 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2144 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2148 currentWebsiteCertificateRadioButton.setOnClickListener((View view) -> {
2149 // Check the current website SSL certificate radio button.
2150 currentWebsiteCertificateRadioButton.setChecked(true);
2152 // Uncheck the saved SSL certificate radio button.
2153 savedSslCertificateRadioButton.setChecked(false);
2155 // Set the background of the current website SSL certificate linear layout to be transparent.
2156 currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.transparent);
2158 // Darken the background of the saved SSL certificate linear layout according to the theme.
2160 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2162 savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2166 // Set the pinned IP addresses switch listener.
2167 pinnedIpAddressesSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
2169 if (isChecked) { // IP addresses pinning is enabled.
2170 // Set the icon according to the theme.
2172 pinnedIpAddressesImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_dark));
2174 pinnedIpAddressesImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_light));
2177 // Update the visibility of the saved IP addresses card view.
2178 if (savedIpAddresses == null) { // There are no saved IP addresses.
2179 savedIpAddressesCardView.setVisibility(View.GONE);
2180 } else { // There are saved IP addresses.
2181 savedIpAddressesCardView.setVisibility(View.VISIBLE);
2184 // Show the current IP addresses card view.
2185 currentIpAddressesCardView.setVisibility(View.VISIBLE);
2187 // Set the status of the radio buttons.
2188 if (savedIpAddressesCardView.getVisibility() == View.VISIBLE) { // The saved IP addresses are visible.
2189 // Check the saved IP addresses radio button.
2190 savedIpAddressesRadioButton.setChecked(true);
2192 // Uncheck the current IP addresses radio button.
2193 currentIpAddressesRadioButton.setChecked(false);
2195 // Set the background of the saved IP addresses linear layout to be transparent.
2196 savedSslCertificateLinearLayout.setBackgroundResource(R.color.transparent);
2198 // Darken the background of the current IP addresses linear layout according to the theme.
2200 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2202 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2204 } else { // The saved IP addresses are not visible.
2205 // Check the current IP addresses radio button.
2206 currentIpAddressesRadioButton.setChecked(true);
2208 // Uncheck the saved IP addresses radio button.
2209 savedIpAddressesRadioButton.setChecked(false);
2211 // Set the background of the current IP addresses linear layout to be transparent.
2212 currentIpAddressesLinearLayout.setBackgroundResource(R.color.transparent);
2214 // Darken the background of the saved IP addresses linear layout according to the theme.
2216 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2218 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2222 // Scroll to the bottom of the card views.
2223 currentIpAddressesCardView.getParent().requestChildFocus(currentIpAddressesCardView, currentIpAddressesCardView);
2224 } else { // IP addresses pinning is disabled.
2225 // Set the icon according to the theme.
2227 pinnedIpAddressesImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_dark));
2229 pinnedIpAddressesImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_light));
2232 // Hide the IP addresses card views.
2233 savedIpAddressesCardView.setVisibility(View.GONE);
2234 currentIpAddressesCardView.setVisibility(View.GONE);
2236 // Uncheck the radio buttons.
2237 savedIpAddressesRadioButton.setChecked(false);
2238 currentIpAddressesRadioButton.setChecked(false);
2242 savedIpAddressesCardView.setOnClickListener((View view) -> {
2243 // Check the saved IP addresses radio button.
2244 savedIpAddressesRadioButton.setChecked(true);
2246 // Uncheck the current website IP addresses radio button.
2247 currentIpAddressesRadioButton.setChecked(false);
2249 // Set the background of the saved IP addresses linear layout to be transparent.
2250 savedIpAddressesLinearLayout.setBackgroundResource(R.color.transparent);
2252 // Darken the background of the current IP addresses linear layout according to the theme.
2254 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2256 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2260 savedIpAddressesRadioButton.setOnClickListener((View view) -> {
2261 // Check the saved IP addresses radio button.
2262 savedIpAddressesRadioButton.setChecked(true);
2264 // Uncheck the current website IP addresses radio button.
2265 currentIpAddressesRadioButton.setChecked(false);
2267 // Set the background of the saved IP addresses linear layout to be transparent.
2268 savedIpAddressesLinearLayout.setBackgroundResource(R.color.transparent);
2270 // Darken the background of the current IP addresses linear layout according to the theme.
2272 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2274 currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2278 currentIpAddressesCardView.setOnClickListener((View view) -> {
2279 // Check the current IP addresses radio button.
2280 currentIpAddressesRadioButton.setChecked(true);
2282 // Uncheck the saved IP addresses radio button.
2283 savedIpAddressesRadioButton.setChecked(false);
2285 // Set the background of the current IP addresses linear layout to be transparent.
2286 currentIpAddressesLinearLayout.setBackgroundResource(R.color.transparent);
2288 // Darken the background of the saved IP addresses linear layout according to the theme.
2290 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2292 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2296 currentIpAddressesRadioButton.setOnClickListener((View view) -> {
2297 // Check the current IP addresses radio button.
2298 currentIpAddressesRadioButton.setChecked(true);
2300 // Uncheck the saved IP addresses radio button.
2301 savedIpAddressesRadioButton.setChecked(false);
2303 // Set the background of the current IP addresses linear layout to be transparent.
2304 currentIpAddressesLinearLayout.setBackgroundResource(R.color.transparent);
2306 // Darken the background of the saved IP addresses linear layout according to the theme.
2308 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
2310 savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
2314 return domainSettingsView;
2317 private boolean checkDomainNameAgainstCertificate(String domainName, String certificateCommonName) {
2318 // Initialize `domainNamesMatch`.
2319 boolean domainNamesMatch = false;
2321 // Check various wildcard permutations if `domainName` and `certificateCommonName` are not empty.
2322 // `noinspection ConstantCondition` removes Android Studio's incorrect lint warning that `domainName` can never be `null`.
2323 if ((domainName != null) && (certificateCommonName != null)) {
2324 // Check if the domains match.
2325 if (domainName.equals(certificateCommonName)) {
2326 domainNamesMatch = true;
2329 // If `domainName` starts with a wildcard, check the base domain against all the subdomains of `certificateCommonName`.
2330 if (!domainNamesMatch && domainName.startsWith("*.") && (domainName.length() > 2)) {
2331 // Remove the initial `*.`.
2332 String baseDomainName = domainName.substring(2);
2334 // Setup a copy of `certificateCommonName` to test subdomains.
2335 String certificateCommonNameSubdomain = certificateCommonName;
2337 // Check all the subdomains in `certificateCommonNameSubdomain` against `baseDomainName`.
2338 while (!domainNamesMatch && certificateCommonNameSubdomain.contains(".")) { // Stop checking if we know that `domainNamesMatch` is `true` or if we run out of `.`.
2339 // Test the `certificateCommonNameSubdomain` against `baseDomainName`.
2340 if (certificateCommonNameSubdomain.equals(baseDomainName)) {
2341 domainNamesMatch = true;
2344 // Strip out the lowest subdomain of `certificateCommonNameSubdomain`.
2346 certificateCommonNameSubdomain = certificateCommonNameSubdomain.substring(certificateCommonNameSubdomain.indexOf(".") + 1);
2347 } catch (IndexOutOfBoundsException e) { // `certificateCommonNameSubdomain` ends with `.`.
2348 certificateCommonNameSubdomain = "";
2353 // If `certificateCommonName` starts with a wildcard, check the base common name against all the subdomains of `domainName`.
2354 if (!domainNamesMatch && certificateCommonName.startsWith("*.") && (certificateCommonName.length() > 2)) {
2355 // Remove the initial `*.`.
2356 String baseCertificateCommonName = certificateCommonName.substring(2);
2358 // Setup a copy of `domainName` to test subdomains.
2359 String domainNameSubdomain = domainName;
2361 // Check all the subdomains in `domainNameSubdomain` against `baseCertificateCommonName`.
2362 while (!domainNamesMatch && domainNameSubdomain.contains(".") && (domainNameSubdomain.length() > 2)) {
2363 // Test the `domainNameSubdomain` against `baseCertificateCommonName`.
2364 if (domainNameSubdomain.equals(baseCertificateCommonName)) {
2365 domainNamesMatch = true;
2368 // Strip out the lowest subdomain of `domainNameSubdomain`.
2370 domainNameSubdomain = domainNameSubdomain.substring(domainNameSubdomain.indexOf(".") + 1);
2371 } catch (IndexOutOfBoundsException e) { // `domainNameSubdomain` ends with `.`.
2372 domainNameSubdomain = "";
2377 // If both names start with a wildcard, check if the root of one contains the root of the other.
2378 if (!domainNamesMatch && domainName.startsWith("*.") && (domainName.length() > 2) && certificateCommonName.startsWith("*.") && (certificateCommonName.length() > 2)) {
2379 // Remove the wildcards.
2380 String rootDomainName = domainName.substring(2);
2381 String rootCertificateCommonName = certificateCommonName.substring(2);
2383 // Check if one name ends with the contents of the other. If so, there will be overlap in the their wildcard subdomains.
2384 if (rootDomainName.endsWith(rootCertificateCommonName) || rootCertificateCommonName.endsWith(rootDomainName)) {
2385 domainNamesMatch = true;
2390 return domainNamesMatch;