2 * Copyright © 2017 Soren Stoutner <soren@stoutner.com>.
4 * This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
6 * Privacy Browser is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * Privacy Browser is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with Privacy Browser. If not, see <http://www.gnu.org/licenses/>.
20 package com.stoutner.privacybrowser.fragments;
22 import android.annotation.SuppressLint;
23 import android.content.Context;
24 import android.content.SharedPreferences;
25 import android.content.res.Resources;
26 import android.database.Cursor;
27 import android.net.http.SslCertificate;
28 import android.os.Build;
29 import android.os.Bundle;
30 // We have to use `android.support.v4.app.Fragment` until minimum API >= 23. Otherwise we cannot call `getContext()`.
31 import android.preference.PreferenceManager;
32 import android.support.v4.app.Fragment;
33 import android.text.Editable;
34 import android.text.SpannableStringBuilder;
35 import android.text.Spanned;
36 import android.text.TextWatcher;
37 import android.text.style.ForegroundColorSpan;
38 import android.view.LayoutInflater;
39 import android.view.View;
40 import android.view.ViewGroup;
41 import android.webkit.WebView;
42 import android.widget.AdapterView;
43 import android.widget.ArrayAdapter;
44 import android.widget.CompoundButton;
45 import android.widget.EditText;
46 import android.widget.ImageView;
47 import android.widget.LinearLayout;
48 import android.widget.RadioButton;
49 import android.widget.Spinner;
50 import android.widget.Switch;
51 import android.widget.TextView;
53 import com.stoutner.privacybrowser.R;
54 import com.stoutner.privacybrowser.activities.MainWebViewActivity;
55 import com.stoutner.privacybrowser.helpers.DomainsDatabaseHelper;
57 import java.text.DateFormat;
58 import java.util.Calendar;
59 import java.util.Date;
61 public class DomainSettingsFragment extends Fragment {
62 // `DATABASE_ID` is used by activities calling this fragment.
63 public static final String DATABASE_ID = "database_id";
65 // `databaseId` is public static so it can be accessed from `DomainsActivity`. It is also used in `onCreate()` and `onCreateView()`.
66 public static int databaseId;
69 public void onCreate(Bundle savedInstanceState) {
70 super.onCreate(savedInstanceState);
72 // Store the database id in `databaseId`.
73 databaseId = getArguments().getInt(DATABASE_ID);
76 // We have to use the deprecated `getDrawable()` until the minimum API >= 21.
77 @SuppressWarnings("deprecation")
79 public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
80 // Inflate `domain_settings_fragment`. `false` does not attach it to the root `container`.
81 View domainSettingsView = inflater.inflate(R.layout.domain_settings_fragment, container, false);
83 // Get a handle for the `Context` and the `Resources`.
84 Context context = getContext();
85 final Resources resources = getResources();
87 // Get a handle for the shared preference.
88 SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
90 // Store the default user agent string values.
91 final String defaultUserAgentString = sharedPreferences.getString("user_agent", "PrivacyBrowser/1.0");
92 final String defaultCustomUserAgentString = sharedPreferences.getString("custom_user_agent", "PrivacyBrowser/1.0");
93 String defaultFontSizeString = sharedPreferences.getString("default_font_size", "100");
94 boolean defaultDisplayWebpageImagesBoolean = sharedPreferences.getBoolean("display_website_images", true);
96 // Get handles for the views in the fragment.
97 final EditText domainNameEditText = (EditText) domainSettingsView.findViewById(R.id.domain_settings_name_edittext);
98 Switch javaScriptEnabledSwitch = (Switch) domainSettingsView.findViewById(R.id.domain_settings_javascript_switch);
99 final ImageView javaScriptImageView = (ImageView) domainSettingsView.findViewById(R.id.domain_settings_javascript_imageview);
100 Switch firstPartyCookiesEnabledSwitch = (Switch) domainSettingsView.findViewById(R.id.domain_settings_first_party_cookies_switch);
101 final ImageView firstPartyCookiesImageView = (ImageView) domainSettingsView.findViewById(R.id.domain_settings_first_party_cookies_imageview);
102 LinearLayout thirdPartyCookiesLinearLayout = (LinearLayout) domainSettingsView.findViewById(R.id.domain_settings_third_party_cookies_linearlayout);
103 final Switch thirdPartyCookiesEnabledSwitch = (Switch) domainSettingsView.findViewById(R.id.domain_settings_third_party_cookies_switch);
104 final ImageView thirdPartyCookiesImageView = (ImageView) domainSettingsView.findViewById(R.id.domain_settings_third_party_cookies_imageview);
105 final Switch domStorageEnabledSwitch = (Switch) domainSettingsView.findViewById(R.id.domain_settings_dom_storage_switch);
106 final ImageView domStorageImageView = (ImageView) domainSettingsView.findViewById(R.id.domain_settings_dom_storage_imageview);
107 Switch formDataEnabledSwitch = (Switch) domainSettingsView.findViewById(R.id.domain_settings_form_data_switch);
108 final ImageView formDataImageView = (ImageView) domainSettingsView.findViewById(R.id.domain_settings_form_data_imageview);
109 Spinner userAgentSpinner = (Spinner) domainSettingsView.findViewById(R.id.domain_settings_user_agent_spinner);
110 final TextView userAgentTextView = (TextView) domainSettingsView.findViewById(R.id.domain_settings_user_agent_textview);
111 final EditText customUserAgentEditText = (EditText) domainSettingsView.findViewById(R.id.domain_settings_custom_user_agent_edittext);
112 Spinner fontSizeSpinner = (Spinner) domainSettingsView.findViewById(R.id.domain_settings_font_size_spinner);
113 final TextView fontSizeTextView = (TextView) domainSettingsView.findViewById(R.id.domain_settings_font_size_textview);
114 final ImageView displayWebpageImagesImageView = (ImageView) domainSettingsView.findViewById(R.id.domain_settings_display_webpage_images_imageview);
115 Spinner displayWebpageImagesSpinner = (Spinner) domainSettingsView.findViewById(R.id.domain_settings_display_webpage_images_spinner);
116 final TextView displayImagesTextView = (TextView) domainSettingsView.findViewById(R.id.domain_settings_display_webpage_images_textview);
117 final ImageView pinnedSslCertificateImageView = (ImageView) domainSettingsView.findViewById(R.id.domain_settings_pinned_ssl_certificate_imageview);
118 Switch pinnedSslCertificateSwitch = (Switch) domainSettingsView.findViewById(R.id.domain_settings_pinned_ssl_certificate_switch);
119 final LinearLayout savedSslCertificateLinearLayout = (LinearLayout) domainSettingsView.findViewById(R.id.saved_ssl_certificate_linearlayout);
120 final RadioButton savedSslCertificateRadioButton = (RadioButton) domainSettingsView.findViewById(R.id.saved_ssl_certificate_radiobutton);
121 final TextView savedSslCertificateIssuedToCNameTextView = (TextView) domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_to_cname);
122 TextView savedSslCertificateIssuedToONameTextView = (TextView) domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_to_oname);
123 TextView savedSslCertificateIssuedToUNameTextView = (TextView) domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_to_uname);
124 TextView savedSslCertificateIssuedByCNameTextView = (TextView) domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_by_cname);
125 TextView savedSslCertificateIssuedByONameTextView = (TextView) domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_by_oname);
126 TextView savedSslCertificateIssuedByUNameTextView = (TextView) domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_by_uname);
127 TextView savedSslCertificateStartDateTextView = (TextView) domainSettingsView.findViewById(R.id.saved_ssl_certificate_start_date);
128 TextView savedSslCertificateEndDateTextView = (TextView) domainSettingsView.findViewById(R.id.saved_ssl_certificate_end_date);
129 final LinearLayout currentWebsiteCertificateLinearLayout = (LinearLayout) domainSettingsView.findViewById(R.id.current_website_certificate_linearlayout);
130 final RadioButton currentWebsiteCertificateRadioButton = (RadioButton) domainSettingsView.findViewById(R.id.current_website_certificate_radiobutton);
131 final TextView currentWebsiteCertificateIssuedToCNameTextView = (TextView) domainSettingsView.findViewById(R.id.current_website_certificate_issued_to_cname);
132 TextView currentWebsiteCertificateIssuedToONameTextView = (TextView) domainSettingsView.findViewById(R.id.current_website_certificate_issued_to_oname);
133 TextView currentWebsiteCertificateIssuedToUNameTextView = (TextView) domainSettingsView.findViewById(R.id.current_website_certificate_issued_to_uname);
134 TextView currentWebsiteCertificateIssuedByCNameTextView = (TextView) domainSettingsView.findViewById(R.id.current_website_certificate_issued_by_cname);
135 TextView currentWebsiteCertificateIssuedByONameTextView = (TextView) domainSettingsView.findViewById(R.id.current_website_certificate_issued_by_oname);
136 TextView currentWebsiteCertificateIssuedByUNameTextView = (TextView) domainSettingsView.findViewById(R.id.current_website_certificate_issued_by_uname);
137 TextView currentWebsiteCertificateStartDateTextView = (TextView) domainSettingsView.findViewById(R.id.current_website_certificate_start_date);
138 TextView currentWebsiteCertificateEndDateTextView = (TextView) domainSettingsView.findViewById(R.id.current_website_certificate_end_date);
139 final TextView noCurrentWebsiteCertificateTextView = (TextView) domainSettingsView.findViewById(R.id.no_current_website_certificate);
141 // Setup the SSL certificate labels.
142 final String cNameLabel = getString(R.string.common_name) + " ";
143 String oNameLabel = getString(R.string.organization) + " ";
144 String uNameLabel = getString(R.string.organizational_unit) + " ";
145 String startDateLabel = getString(R.string.start_date) + " ";
146 String endDateLabel = getString(R.string.end_date) + " ";
148 // Get the current website SSL certificate
149 final SslCertificate currentWebsiteSslCertificate = MainWebViewActivity.sslCertificate;
151 // Initialize the database handler. The two `nulls` do not specify the database name or a `CursorFactory`. The `0` specifies the database version, but that is ignored and set instead using a constant in `DomainsDatabaseHelper`.
152 DomainsDatabaseHelper domainsDatabaseHelper = new DomainsDatabaseHelper(context, null, null, 0);
154 // Get the database `Cursor` for this ID and move it to the first row.
155 Cursor domainCursor = domainsDatabaseHelper.getCursorForId(databaseId);
156 domainCursor.moveToFirst();
158 // Save the `Cursor` entries as variables.
159 String domainNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.DOMAIN_NAME));
160 int javaScriptEnabledInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_JAVASCRIPT));
161 int firstPartyCookiesEnabledInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FIRST_PARTY_COOKIES));
162 int thirdPartyCookiesEnabledInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_THIRD_PARTY_COOKIES));
163 int domStorageEnabledInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_DOM_STORAGE));
164 int formDataEnabledInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FORM_DATA));
165 final String currentUserAgentString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.USER_AGENT));
166 int fontSizeInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.FONT_SIZE));
167 int displayImagesInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.DISPLAY_IMAGES));
168 int pinnedSslCertificateInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.PINNED_SSL_CERTIFICATE));
169 final String savedSslCertificateIssuedToCNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_TO_COMMON_NAME));
170 String savedSslCertificateIssuedToONameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_TO_ORGANIZATION));
171 String savedSslCertificateIssuedToUNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_TO_ORGANIZATIONAL_UNIT));
172 String savedSslCertificateIssuedByCNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_BY_COMMON_NAME));
173 String savedSslCertificateIssuedByONameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_BY_ORGANIZATION));
174 String savedSslCertificateIssuedByUNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_BY_ORGANIZATIONAL_UNIT));
176 // Initialize the saved SSL certificate date variables.
177 Date savedSslCertificateStartDate = null;
178 Date savedSslCertificateEndDate = null;
180 // Only get the saved SSL certificate dates from the cursor if they are not set to `0`.
181 if (domainCursor.getLong(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_START_DATE)) != 0) {
182 savedSslCertificateStartDate = new Date(domainCursor.getLong(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_START_DATE)));
185 if (domainCursor.getLong(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_END_DATE)) != 0) {
186 savedSslCertificateEndDate = new Date(domainCursor.getLong(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_END_DATE)));
189 // Create `ArrayAdapters` for the `Spinners`and their `entry values`.
190 ArrayAdapter<CharSequence> userAgentArrayAdapter = ArrayAdapter.createFromResource(context, R.array.domain_settings_user_agent_entries, R.layout.spinner_item);
191 final ArrayAdapter<CharSequence> userAgentEntryValuesArrayAdapter = ArrayAdapter.createFromResource(context, R.array.domain_settings_user_agent_entry_values, R.layout.spinner_item);
192 ArrayAdapter<CharSequence> fontSizeArrayAdapter = ArrayAdapter.createFromResource(context, R.array.domain_settings_font_size_entries, R.layout.spinner_item);
193 ArrayAdapter<CharSequence> fontSizeEntryValuesArrayAdapter = ArrayAdapter.createFromResource(context, R.array.domain_settings_font_size_entry_values, R.layout.spinner_item);
194 final ArrayAdapter<CharSequence> displayImagesArrayAdapter = ArrayAdapter.createFromResource(context, R.array.display_website_images_array, R.layout.spinner_item);
196 // Set the `DropDownViewResource` on the `Spinners`.
197 userAgentArrayAdapter.setDropDownViewResource(R.layout.spinner_dropdown_item);
198 fontSizeArrayAdapter.setDropDownViewResource(R.layout.spinner_dropdown_item);
199 displayImagesArrayAdapter.setDropDownViewResource(R.layout.spinner_dropdown_item);
201 // Set the `ArrayAdapters` for the `Spinners`.
202 userAgentSpinner.setAdapter(userAgentArrayAdapter);
203 fontSizeSpinner.setAdapter(fontSizeArrayAdapter);
204 displayWebpageImagesSpinner.setAdapter(displayImagesArrayAdapter);
206 // Create a `SpannableStringBuilder` for each `TextView` that needs multiple colors of text.
207 SpannableStringBuilder savedSslCertificateIssuedToCNameStringBuilder = new SpannableStringBuilder(cNameLabel + savedSslCertificateIssuedToCNameString);
208 SpannableStringBuilder savedSslCertificateIssuedToONameStringBuilder = new SpannableStringBuilder(oNameLabel + savedSslCertificateIssuedToONameString);
209 SpannableStringBuilder savedSslCertificateIssuedToUNameStringBuilder = new SpannableStringBuilder(uNameLabel + savedSslCertificateIssuedToUNameString);
210 SpannableStringBuilder savedSslCertificateIssuedByCNameStringBuilder = new SpannableStringBuilder(cNameLabel + savedSslCertificateIssuedByCNameString);
211 SpannableStringBuilder savedSslCertificateIssuedByONameStringBuilder = new SpannableStringBuilder(oNameLabel + savedSslCertificateIssuedByONameString);
212 SpannableStringBuilder savedSslCertificateIssuedByUNameStringBuilder = new SpannableStringBuilder(uNameLabel + savedSslCertificateIssuedByUNameString);
214 // Initialize the `SpannableStringBuilders` for the SSL certificate dates.
215 SpannableStringBuilder savedSslCertificateStartDateStringBuilder;
216 SpannableStringBuilder savedSslCertificateEndDateStringBuilder;
218 // Leave the SSL certificate dates empty if they are `null`.
219 if (savedSslCertificateStartDate == null) {
220 savedSslCertificateStartDateStringBuilder = new SpannableStringBuilder(startDateLabel);
222 savedSslCertificateStartDateStringBuilder = new SpannableStringBuilder(startDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(savedSslCertificateStartDate));
225 if (savedSslCertificateEndDate == null) {
226 savedSslCertificateEndDateStringBuilder = new SpannableStringBuilder(endDateLabel);
228 savedSslCertificateEndDateStringBuilder = new SpannableStringBuilder(endDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(savedSslCertificateEndDate));
231 // Create a red `ForegroundColorSpan`. We have to use the deprecated `getColor` until API >= 23.
232 final ForegroundColorSpan redColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.red_a700));
234 // Create a blue `ForegroundColorSpan`.
235 final ForegroundColorSpan blueColorSpan;
237 // Set `blueColorSpan` according to the theme. We have to use the deprecated `getColor()` until API >= 23.
238 if (MainWebViewActivity.darkTheme) {
239 //noinspection deprecation
240 blueColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.blue_400));
242 //noinspection deprecation
243 blueColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.blue_700));
246 // Set the domain name from the the database cursor.
247 domainNameEditText.setText(domainNameString);
249 // Update the certificates' `Common Name` color when the domain name text changes.
250 domainNameEditText.addTextChangedListener(new TextWatcher() {
252 public void beforeTextChanged(CharSequence s, int start, int count, int after) {
257 public void onTextChanged(CharSequence s, int start, int before, int count) {
262 public void afterTextChanged(Editable s) {
263 // Get the new domain name.
264 String newDomainName = domainNameEditText.getText().toString();
266 // Check the saved SSL certificate against the new domain name.
267 boolean savedSslCertificateMatchesNewDomainName = checkDomainNameAgainstCertificate(newDomainName, savedSslCertificateIssuedToCNameString);
269 // Create a `SpannableStringBuilder` for the saved certificate `Common Name`.
270 SpannableStringBuilder savedSslCertificateCommonNameStringBuilder = new SpannableStringBuilder(cNameLabel + savedSslCertificateIssuedToCNameString);
272 // Format the saved certificate `Common Name` color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
273 if (savedSslCertificateMatchesNewDomainName) {
274 savedSslCertificateCommonNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), savedSslCertificateCommonNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
276 savedSslCertificateCommonNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), savedSslCertificateCommonNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
279 // Update `savedSslCertificateIssuedToCNameTextView`.
280 savedSslCertificateIssuedToCNameTextView.setText(savedSslCertificateCommonNameStringBuilder);
282 // Update the current website certificate if it exists.
283 if (currentWebsiteSslCertificate != null) {
284 // Get the current website certificate `Common Name`.
285 String currentWebsiteCertificateCommonName = currentWebsiteSslCertificate.getIssuedTo().getCName();
287 // Check the current website certificate against the new domain name.
288 boolean currentWebsiteCertificateMatchesNewDomainName = checkDomainNameAgainstCertificate(newDomainName, currentWebsiteCertificateCommonName);
290 // Create a `SpannableStringBuilder` for the current website certificate `Common Name`.
291 SpannableStringBuilder currentWebsiteCertificateCommonNameStringBuilder = new SpannableStringBuilder(cNameLabel + currentWebsiteCertificateCommonName);
293 // Format the current certificate `Common Name` color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
294 if (currentWebsiteCertificateMatchesNewDomainName) {
295 currentWebsiteCertificateCommonNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), currentWebsiteCertificateCommonNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
297 currentWebsiteCertificateCommonNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), currentWebsiteCertificateCommonNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
300 // Update `currentWebsiteCertificateIssuedToCNameTextView`.
301 currentWebsiteCertificateIssuedToCNameTextView.setText(currentWebsiteCertificateCommonNameStringBuilder);
306 // Set the JavaScript status.
307 if (javaScriptEnabledInt == 1) { // JavaScript is enabled.
308 javaScriptEnabledSwitch.setChecked(true);
309 javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.javascript_enabled));
310 } else { // JavaScript is disabled.
311 javaScriptEnabledSwitch.setChecked(false);
312 javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.privacy_mode));
315 // Set the first-party cookies status. Once minimum API >= 21 we can use a selector as the tint mode instead of specifying different icons.
316 if (firstPartyCookiesEnabledInt == 1) { // First-party cookies are enabled.
317 firstPartyCookiesEnabledSwitch.setChecked(true);
318 firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_enabled));
319 } else { // First-party cookies are disabled.
320 firstPartyCookiesEnabledSwitch.setChecked(false);
322 // Set the icon according to the theme.
323 if (MainWebViewActivity.darkTheme) {
324 firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_dark));
326 firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_light));
330 // Only display third-party cookies if SDK_INT >= 21.
331 if (Build.VERSION.SDK_INT >= 21) { // Third-party cookies can be configured for API >= 21.
332 // Only enable third-party-cookies if first-party cookies are enabled.
333 if (firstPartyCookiesEnabledInt == 1) { // First-party cookies are enabled.
334 // Set the third-party cookies status. Once minimum API >= 21 we can use a selector as the tint mode instead of specifying different icons.
335 if (thirdPartyCookiesEnabledInt == 1) { // Both first-party and third-party cookies are enabled.
336 thirdPartyCookiesEnabledSwitch.setChecked(true);
337 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_warning));
338 } else { // First party cookies are enabled but third-party cookies are disabled.
339 thirdPartyCookiesEnabledSwitch.setChecked(false);
341 // Set the icon according to the theme.
342 if (MainWebViewActivity.darkTheme) {
343 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_dark));
345 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_light));
348 } else { // First-party cookies are disabled.
349 // Set the status of third-party cookies.
350 if (thirdPartyCookiesEnabledInt == 1) {
351 thirdPartyCookiesEnabledSwitch.setChecked(true);
353 thirdPartyCookiesEnabledSwitch.setChecked(false);
356 // Disable the third-party cookies switch.
357 thirdPartyCookiesEnabledSwitch.setEnabled(false);
359 // Set the icon according to the theme.
360 if (MainWebViewActivity.darkTheme) {
361 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_ghosted_dark));
363 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_ghosted_light));
366 } else { // Third-party cookies cannot be configured for API <= 21.
367 // Hide the `LinearLayout` for third-party cookies.
368 thirdPartyCookiesLinearLayout.setVisibility(View.GONE);
371 // Only enable DOM storage if JavaScript is enabled.
372 if (javaScriptEnabledInt == 1) { // JavaScript is enabled.
373 // Set the DOM storage status. Once minimum API >= 21 we can use a selector as the tint mode instead of specifying different icons.
374 if (domStorageEnabledInt == 1) { // Both JavaScript and DOM storage are enabled.
375 domStorageEnabledSwitch.setChecked(true);
376 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_enabled));
377 } else { // JavaScript is enabled but DOM storage is disabled.
378 // Set the DOM storage switch to off.
379 domStorageEnabledSwitch.setChecked(false);
381 // Set the icon according to the theme.
382 if (MainWebViewActivity.darkTheme) {
383 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_dark));
385 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_light));
388 } else { // JavaScript is disabled.
389 // Set the checked status of DOM storage.
390 if (domStorageEnabledInt == 1) { // DOM storage is enabled but JavaScript is disabled.
391 domStorageEnabledSwitch.setChecked(true);
392 } else { // Both JavaScript and DOM storage are disabled.
393 domStorageEnabledSwitch.setChecked(false);
396 // Disable `domStorageEnabledSwitch`.
397 domStorageEnabledSwitch.setEnabled(false);
399 // Set the icon according to the theme.
400 if (MainWebViewActivity.darkTheme) {
401 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_dark));
403 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_light));
407 // Set the form data status. Once minimum API >= 21 we can use a selector as the tint mode instead of specifying different icons.
408 if (formDataEnabledInt == 1) { // Form data is enabled.
409 formDataEnabledSwitch.setChecked(true);
410 formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_enabled));
411 } else { // Form data is disabled.
412 // Set the form data switch to off.
413 formDataEnabledSwitch.setChecked(false);
415 // Set the icon according to the theme.
416 if (MainWebViewActivity.darkTheme) {
417 formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_disabled_dark));
419 formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_disabled_light));
423 // We need to inflated a `WebView` to get the default user agent.
424 // `@SuppressLint("InflateParams")` removes the warning about using `null` as the `ViewGroup`, which in this case makes sense because we don't want to display `bare_webview` on the screen. `false` does not attach the view to the root.
425 @SuppressLint("InflateParams") View bareWebViewLayout = inflater.inflate(R.layout.bare_webview, null, false);
426 WebView bareWebView = (WebView) bareWebViewLayout.findViewById(R.id.bare_webview);
427 final String webViewDefaultUserAgentString = bareWebView.getSettings().getUserAgentString();
429 // Get the position of the user agent in `userAgentEntryValuesArrayAdapter`.
430 int userAgentArrayPosition = userAgentEntryValuesArrayAdapter.getPosition(currentUserAgentString);
432 // Set the user agent.
433 if (userAgentArrayPosition == -1) { // We are using a custom `userAgentString`.
434 // Set `userAgentSpinner` to `Custom`.
435 userAgentSpinner.setSelection(userAgentEntryValuesArrayAdapter.getPosition("Custom user agent"));
437 // Hide `userAgentTextView`.
438 userAgentTextView.setVisibility(View.GONE);
440 // Show `customUserAgentEditText` and set `userAgentString` as the text.
441 customUserAgentEditText.setVisibility(View.VISIBLE);
442 customUserAgentEditText.setText(currentUserAgentString);
443 } else{ // We are using one of the preset user agents.
444 // Set the `userAgentSpinner` selection.
445 userAgentSpinner.setSelection(userAgentArrayPosition);
447 // Show `userAgentTextView`.
448 userAgentTextView.setVisibility(View.VISIBLE);
450 // Hide `customUserAgentEditText`.
451 customUserAgentEditText.setVisibility(View.GONE);
453 // Set the user agent text.
454 switch (currentUserAgentString) {
455 case "System default user agent":
456 // Display the user agent text string.
457 switch (defaultUserAgentString) {
458 case "WebView default user agent":
459 // Display the `WebView` default user agent.
460 userAgentTextView.setText(webViewDefaultUserAgentString);
463 case "Custom user agent":
464 // Display the custom user agent.
465 userAgentTextView.setText(defaultCustomUserAgentString);
469 // Display the text from `defaultUserAgentString`.
470 userAgentTextView.setText(defaultUserAgentString);
474 case "WebView default user agent":
475 // Display the `WebView` default user agent.
476 userAgentTextView.setText(webViewDefaultUserAgentString);
480 // Display the text from `currentUserAgentString`.
481 userAgentTextView.setText(currentUserAgentString);
485 // Set the selected font size.
486 int fontSizeArrayPosition = fontSizeEntryValuesArrayAdapter.getPosition(String.valueOf(fontSizeInt));
487 fontSizeSpinner.setSelection(fontSizeArrayPosition);
489 // Set the default font size text.
490 int defaultFontSizeArrayPosition = fontSizeEntryValuesArrayAdapter.getPosition(defaultFontSizeString);
491 fontSizeTextView.setText(fontSizeArrayAdapter.getItem(defaultFontSizeArrayPosition));
493 // Set the display options for `fontSizeTextView`.
494 if (fontSizeArrayPosition == 0) { // System default font size is selected. Display `fontSizeTextView`.
495 fontSizeTextView.setVisibility(View.VISIBLE);
496 } else { // A custom font size is specified. Hide `fontSizeTextView`.
497 fontSizeTextView.setVisibility(View.GONE);
500 // Set the selected display website images mode.
501 displayWebpageImagesSpinner.setSelection(displayImagesInt);
503 // Set the default display images text.
504 if (defaultDisplayWebpageImagesBoolean) {
505 displayImagesTextView.setText(displayImagesArrayAdapter.getItem(1));
507 displayImagesTextView.setText(displayImagesArrayAdapter.getItem(2));
510 // Set the display website images icon and `TextView` settings.
511 switch (displayImagesInt) {
512 case DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_SYSTEM_DEFAULT:
513 if (MainWebViewActivity.displayWebpageImagesBoolean) {
514 // Set the icon according to the theme.
515 if (MainWebViewActivity.darkTheme) {
516 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_dark));
518 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_light));
521 // Set the icon according to the theme.
522 if (MainWebViewActivity.darkTheme) {
523 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_dark));
525 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_light));
529 // Show `displayImagesTextView`.
530 displayImagesTextView.setVisibility(View.VISIBLE);
533 case DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_ENABLED:
534 // Set the icon according to the theme.
535 if (MainWebViewActivity.darkTheme) {
536 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_dark));
538 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_light));
541 // Hide `displayImagesTextView`.
542 displayImagesTextView.setVisibility(View.GONE);
545 case DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_DISABLED:
546 // Set the icon according to the theme.
547 if (MainWebViewActivity.darkTheme) {
548 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_dark));
550 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_light));
553 // Hide `displayImagesTextView`.
554 displayImagesTextView.setVisibility(View.GONE);
558 // Set the pinned SSL certificate icon.
559 if (pinnedSslCertificateInt == 1) { // Pinned SSL certificate is enabled.
561 pinnedSslCertificateSwitch.setChecked(true);
563 // Set the icon according to the theme.
564 if (MainWebViewActivity.darkTheme) {
565 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_dark));
567 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_light));
569 } else { // Pinned SSL certificate is disabled.
570 // Uncheck the switch.
571 pinnedSslCertificateSwitch.setChecked(false);
573 // Set the icon according to the theme.
574 if (MainWebViewActivity.darkTheme) {
575 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_dark));
577 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_light));
581 // Store the current date.
582 Date currentDate = Calendar.getInstance().getTime();
584 // Setup the `StringBuilders` to display the general certificate information in blue. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
585 savedSslCertificateIssuedToONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), savedSslCertificateIssuedToONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
586 savedSslCertificateIssuedToUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), savedSslCertificateIssuedToUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
587 savedSslCertificateIssuedByCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), savedSslCertificateIssuedByCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
588 savedSslCertificateIssuedByONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), savedSslCertificateIssuedByONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
589 savedSslCertificateIssuedByUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), savedSslCertificateIssuedByUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
591 // Check the certificate `Common Name` against the domain name.
592 boolean savedSSlCertificateCommonNameMatchesDomainName = checkDomainNameAgainstCertificate(domainNameString, savedSslCertificateIssuedToCNameString);
594 // Format the `issuedToCommonName` color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
595 if (savedSSlCertificateCommonNameMatchesDomainName) {
596 savedSslCertificateIssuedToCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), savedSslCertificateIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
598 savedSslCertificateIssuedToCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), savedSslCertificateIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
601 // Format the start date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
602 if ((savedSslCertificateStartDate != null) && savedSslCertificateStartDate.after(currentDate)) { // The certificate start date is in the future.
603 savedSslCertificateStartDateStringBuilder.setSpan(redColorSpan, startDateLabel.length(), savedSslCertificateStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
604 } else { // The certificate start date is in the past.
605 savedSslCertificateStartDateStringBuilder.setSpan(blueColorSpan, startDateLabel.length(), savedSslCertificateStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
608 // Format the end date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
609 if ((savedSslCertificateEndDate != null) && savedSslCertificateEndDate.before(currentDate)) { // The certificate end date is in the past.
610 savedSslCertificateEndDateStringBuilder.setSpan(redColorSpan, endDateLabel.length(), savedSslCertificateEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
611 } else { // The certificate end date is in the future.
612 savedSslCertificateEndDateStringBuilder.setSpan(blueColorSpan, endDateLabel.length(), savedSslCertificateEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
615 // Display the current website SSL certificate strings.
616 savedSslCertificateIssuedToCNameTextView.setText(savedSslCertificateIssuedToCNameStringBuilder);
617 savedSslCertificateIssuedToONameTextView.setText(savedSslCertificateIssuedToONameStringBuilder);
618 savedSslCertificateIssuedToUNameTextView.setText(savedSslCertificateIssuedToUNameStringBuilder);
619 savedSslCertificateIssuedByCNameTextView.setText(savedSslCertificateIssuedByCNameStringBuilder);
620 savedSslCertificateIssuedByONameTextView.setText(savedSslCertificateIssuedByONameStringBuilder);
621 savedSslCertificateIssuedByUNameTextView.setText(savedSslCertificateIssuedByUNameStringBuilder);
622 savedSslCertificateStartDateTextView.setText(savedSslCertificateStartDateStringBuilder);
623 savedSslCertificateEndDateTextView.setText(savedSslCertificateEndDateStringBuilder);
625 // Populate the current website SSL certificate if there is one.
626 if (currentWebsiteSslCertificate != null) {
627 // Get the strings from the SSL certificate.
628 String currentWebsiteCertificateIssuedToCNameString = currentWebsiteSslCertificate.getIssuedTo().getCName();
629 String currentWebsiteCertificateIssuedToONameString = currentWebsiteSslCertificate.getIssuedTo().getOName();
630 String currentWebsiteCertificateIssuedToUNameString = currentWebsiteSslCertificate.getIssuedTo().getUName();
631 String currentWebsiteCertificateIssuedByCNameString = currentWebsiteSslCertificate.getIssuedBy().getCName();
632 String currentWebsiteCertificateIssuedByONameString = currentWebsiteSslCertificate.getIssuedBy().getOName();
633 String currentWebsiteCertificateIssuedByUNameString = currentWebsiteSslCertificate.getIssuedBy().getUName();
634 Date currentWebsiteCertificateStartDate = currentWebsiteSslCertificate.getValidNotBeforeDate();
635 Date currentWebsiteCertificateEndDate = currentWebsiteSslCertificate.getValidNotAfterDate();
637 // Create a `SpannableStringBuilder` for each `TextView` that needs multiple colors of text.
638 SpannableStringBuilder currentWebsiteCertificateIssuedToCNameStringBuilder = new SpannableStringBuilder(cNameLabel + currentWebsiteCertificateIssuedToCNameString);
639 SpannableStringBuilder currentWebsiteCertificateIssuedToONameStringBuilder = new SpannableStringBuilder(oNameLabel + currentWebsiteCertificateIssuedToONameString);
640 SpannableStringBuilder currentWebsiteCertificateIssuedToUNameStringBuilder = new SpannableStringBuilder(uNameLabel + currentWebsiteCertificateIssuedToUNameString);
641 SpannableStringBuilder currentWebsiteCertificateIssuedByCNameStringBuilder = new SpannableStringBuilder(cNameLabel + currentWebsiteCertificateIssuedByCNameString);
642 SpannableStringBuilder currentWebsiteCertificateIssuedByONameStringBuilder = new SpannableStringBuilder(oNameLabel + currentWebsiteCertificateIssuedByONameString);
643 SpannableStringBuilder currentWebsiteCertificateIssuedByUNameStringBuilder = new SpannableStringBuilder(uNameLabel + currentWebsiteCertificateIssuedByUNameString);
644 SpannableStringBuilder currentWebsiteCertificateStartDateStringBuilder = new SpannableStringBuilder(startDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(currentWebsiteCertificateStartDate));
645 SpannableStringBuilder currentWebsiteCertificateEndDateStringBuilder = new SpannableStringBuilder(endDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(currentWebsiteCertificateEndDate));
647 // Setup the `StringBuilders` to display the general certificate information in blue. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
648 currentWebsiteCertificateIssuedToONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), currentWebsiteCertificateIssuedToONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
649 currentWebsiteCertificateIssuedToUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), currentWebsiteCertificateIssuedToUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
650 currentWebsiteCertificateIssuedByCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), currentWebsiteCertificateIssuedByCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
651 currentWebsiteCertificateIssuedByONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), currentWebsiteCertificateIssuedByONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
652 currentWebsiteCertificateIssuedByUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), currentWebsiteCertificateIssuedByUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
654 // Check the certificate `Common Name` against the domain name.
655 boolean currentWebsiteCertificateCommonNameMatchesDomainName = checkDomainNameAgainstCertificate(domainNameString, currentWebsiteCertificateIssuedToCNameString);
657 // Format the `issuedToCommonName` color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
658 if (currentWebsiteCertificateCommonNameMatchesDomainName) {
659 currentWebsiteCertificateIssuedToCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), currentWebsiteCertificateIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
661 currentWebsiteCertificateIssuedToCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), currentWebsiteCertificateIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
664 // Format the start date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
665 if (currentWebsiteCertificateStartDate.after(currentDate)) { // The certificate start date is in the future.
666 currentWebsiteCertificateStartDateStringBuilder.setSpan(redColorSpan, startDateLabel.length(), currentWebsiteCertificateStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
667 } else { // The certificate start date is in the past.
668 currentWebsiteCertificateStartDateStringBuilder.setSpan(blueColorSpan, startDateLabel.length(), currentWebsiteCertificateStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
671 // Format the end date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
672 if (currentWebsiteCertificateEndDate.before(currentDate)) { // The certificate end date is in the past.
673 currentWebsiteCertificateEndDateStringBuilder.setSpan(redColorSpan, endDateLabel.length(), currentWebsiteCertificateEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
674 } else { // The certificate end date is in the future.
675 currentWebsiteCertificateEndDateStringBuilder.setSpan(blueColorSpan, endDateLabel.length(), currentWebsiteCertificateEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
678 // Display the current website SSL certificate strings.
679 currentWebsiteCertificateIssuedToCNameTextView.setText(currentWebsiteCertificateIssuedToCNameStringBuilder);
680 currentWebsiteCertificateIssuedToONameTextView.setText(currentWebsiteCertificateIssuedToONameStringBuilder);
681 currentWebsiteCertificateIssuedToUNameTextView.setText(currentWebsiteCertificateIssuedToUNameStringBuilder);
682 currentWebsiteCertificateIssuedByCNameTextView.setText(currentWebsiteCertificateIssuedByCNameStringBuilder);
683 currentWebsiteCertificateIssuedByONameTextView.setText(currentWebsiteCertificateIssuedByONameStringBuilder);
684 currentWebsiteCertificateIssuedByUNameTextView.setText(currentWebsiteCertificateIssuedByUNameStringBuilder);
685 currentWebsiteCertificateStartDateTextView.setText(currentWebsiteCertificateStartDateStringBuilder);
686 currentWebsiteCertificateEndDateTextView.setText(currentWebsiteCertificateEndDateStringBuilder);
689 // Set the initial display status for the SSL certificates.
690 if (pinnedSslCertificateSwitch.isChecked()) {
691 // Set the visibility of the saved SSL certificate.
692 if (savedSslCertificateIssuedToCNameString == null) {
693 savedSslCertificateLinearLayout.setVisibility(View.GONE);
695 savedSslCertificateLinearLayout.setVisibility(View.VISIBLE);
698 // Set the visibility of the current website SSL certificate.
699 if (currentWebsiteSslCertificate == null) {
700 // Hide the SSL certificate.
701 currentWebsiteCertificateLinearLayout.setVisibility(View.GONE);
703 // Show the instruction.
704 noCurrentWebsiteCertificateTextView.setVisibility(View.VISIBLE);
706 // Show the SSL certificate.
707 currentWebsiteCertificateLinearLayout.setVisibility(View.VISIBLE);
709 // Hide the instruction.
710 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
713 // Set the status of the radio buttons.
714 if (savedSslCertificateLinearLayout.getVisibility() == View.VISIBLE) { // The saved SSL certificate is displayed.
715 savedSslCertificateRadioButton.setChecked(true);
716 currentWebsiteCertificateRadioButton.setChecked(false);
717 } else if (currentWebsiteCertificateLinearLayout.getVisibility() == View.VISIBLE) { // The saved SSL certificate is hidden but the current website SSL certificate is visible.
718 currentWebsiteCertificateRadioButton.setChecked(true);
719 savedSslCertificateRadioButton.setChecked(false);
720 } else { // Neither SSL certificate is visible.
721 savedSslCertificateRadioButton.setChecked(false);
722 currentWebsiteCertificateRadioButton.setChecked(false);
724 } else { // `pinnedSslCertificateSwitch` is not checked.
725 // Hide the SSl certificates and instructions.
726 savedSslCertificateLinearLayout.setVisibility(View.GONE);
727 currentWebsiteCertificateLinearLayout.setVisibility(View.GONE);
728 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
730 // Uncheck the radio buttons.
731 savedSslCertificateRadioButton.setChecked(false);
732 currentWebsiteCertificateRadioButton.setChecked(false);
736 // Set the `javaScriptEnabledSwitch` `OnCheckedChangeListener()`.
737 javaScriptEnabledSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
739 public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
740 if (isChecked) { // JavaScript is enabled.
741 // Update the JavaScript icon.
742 javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.javascript_enabled));
744 // Enable the DOM storage `Switch`.
745 domStorageEnabledSwitch.setEnabled(true);
747 // Update the DOM storage icon.
748 if (domStorageEnabledSwitch.isChecked()) { // DOM storage is enabled.
749 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_enabled));
750 } else { // DOM storage is disabled.
751 // Set the icon according to the theme.
752 if (MainWebViewActivity.darkTheme) {
753 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_dark));
755 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_light));
758 } else { // JavaScript is disabled.
759 // Update the JavaScript icon.
760 javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.privacy_mode));
762 // Disable the DOM storage `Switch`.
763 domStorageEnabledSwitch.setEnabled(false);
765 // Set the DOM storage icon according to the theme.
766 if (MainWebViewActivity.darkTheme) {
767 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_dark));
769 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_light));
775 // Set the `firstPartyCookiesEnabledSwitch` `OnCheckedChangeListener()`.
776 firstPartyCookiesEnabledSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
778 public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
779 if (isChecked) { // First-party cookies are enabled.
780 // Update the first-party cookies icon.
781 firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_enabled));
783 // Enable the third-party cookies `Switch`.
784 thirdPartyCookiesEnabledSwitch.setEnabled(true);
786 // Update the third-party cookies icon.
787 if (thirdPartyCookiesEnabledSwitch.isChecked()) { // Third-party cookies are enabled.
788 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_warning));
789 } else { // Third-party cookies are disabled.
790 // Set the third-party cookies icon according to the theme.
791 if (MainWebViewActivity.darkTheme) {
792 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_dark));
794 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_light));
797 } else { // First-party cookies are disabled.
798 // Update the first-party cookies icon according to the theme.
799 if (MainWebViewActivity.darkTheme) {
800 firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_dark));
802 firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_light));
805 // Disable the third-party cookies `Switch`.
806 thirdPartyCookiesEnabledSwitch.setEnabled(false);
808 // Set the third-party cookies icon according to the theme.
809 if (MainWebViewActivity.darkTheme) {
810 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_ghosted_dark));
812 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_ghosted_light));
818 // Set the `thirdPartyCookiesEnabledSwitch` `OnCheckedChangeListener()`.
819 thirdPartyCookiesEnabledSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
821 public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
824 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_warning));
826 // Update the third-party cookies icon according to the theme.
827 if (MainWebViewActivity.darkTheme) {
828 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_dark));
830 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_light));
836 // Set the `domStorageEnabledSwitch` `OnCheckedChangeListener()`.
837 domStorageEnabledSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
839 public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
842 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_enabled));
844 // Set the icon according to the theme.
845 if (MainWebViewActivity.darkTheme) {
846 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_dark));
848 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_light));
854 // Set the `formDataEnabledSwitch` `OnCheckedChangeListener()`.
855 formDataEnabledSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
857 public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
860 formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_enabled));
862 // Set the icon according to the theme.
863 if (MainWebViewActivity.darkTheme) {
864 formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_disabled_dark));
866 formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_disabled_light));
872 // Set the `userAgentSpinner` `onItemClickListener()`.
873 userAgentSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
875 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
876 // Store the new user agent string.
877 String newUserAgentString = resources.getStringArray(R.array.domain_settings_user_agent_entry_values)[position];
879 // Set the new user agent.
880 switch (newUserAgentString) {
881 case "System default user agent":
882 // Show `userAgentTextView`.
883 userAgentTextView.setVisibility(View.VISIBLE);
885 // Hide `customUserAgentEditText`.
886 customUserAgentEditText.setVisibility(View.GONE);
888 // Set the user text.
889 switch (defaultUserAgentString) {
890 case "WebView default user agent":
891 // Display the `WebView` default user agent.
892 userAgentTextView.setText(webViewDefaultUserAgentString);
895 case "Custom user agent":
896 // Display the custom user agent.
897 userAgentTextView.setText(defaultCustomUserAgentString);
901 // Display the text from `defaultUserAgentString`.
902 userAgentTextView.setText(defaultUserAgentString);
906 case "WebView default user agent":
907 // Show `userAgentTextView` and set the text.
908 userAgentTextView.setVisibility(View.VISIBLE);
909 userAgentTextView.setText(webViewDefaultUserAgentString);
911 // Hide `customUserAgentEditText`.
912 customUserAgentEditText.setVisibility(View.GONE);
915 case "Custom user agent":
916 // Hide `userAgentTextView`.
917 userAgentTextView.setVisibility(View.GONE);
919 // Show `customUserAgentEditText` and set `userAgentString` as the text.
920 customUserAgentEditText.setVisibility(View.VISIBLE);
921 customUserAgentEditText.setText(currentUserAgentString);
925 // Show `userAgentTextView` and set the text.
926 userAgentTextView.setVisibility(View.VISIBLE);
927 userAgentTextView.setText(newUserAgentString);
929 // Hide `customUserAgentEditText`.
930 customUserAgentEditText.setVisibility(View.GONE);
935 public void onNothingSelected(AdapterView<?> parent) {
940 // Set the `fontSizeSpinner` `onItemSelectedListener()`.
941 fontSizeSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
943 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
944 // Update the display options for `fontSizeTextView`.
945 if (position == 0) { // System default font size has been selected. Display `fontSizeTextView`.
946 fontSizeTextView.setVisibility(View.VISIBLE);
947 } else { // A custom font size has been selected. Hide `fontSizeTextView`.
948 fontSizeTextView.setVisibility(View.GONE);
953 public void onNothingSelected(AdapterView<?> parent) {
958 // Set the `displayWebpageImagesSpinner` `onItemSelectedListener()`.
959 displayWebpageImagesSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
961 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
962 // Update the icon and the visibility of `displayImagesTextView`.
964 case DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_SYSTEM_DEFAULT:
965 if (MainWebViewActivity.displayWebpageImagesBoolean) {
966 // Set the icon according to the theme.
967 if (MainWebViewActivity.darkTheme) {
968 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_dark));
970 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_light));
973 // Set the icon according to the theme.
974 if (MainWebViewActivity.darkTheme) {
975 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_dark));
977 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_light));
981 // Show `displayImagesTextView`.
982 displayImagesTextView.setVisibility(View.VISIBLE);
985 case DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_ENABLED:
986 // Set the icon according to the theme.
987 if (MainWebViewActivity.darkTheme) {
988 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_dark));
990 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_light));
993 // Hide `displayImagesTextView`.
994 displayImagesTextView.setVisibility(View.GONE);
997 case DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_DISABLED:
998 // Set the icon according to the theme.
999 if (MainWebViewActivity.darkTheme) {
1000 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_dark));
1002 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_light));
1005 // Hide `displayImagesTextView`.
1006 displayImagesTextView.setVisibility(View.GONE);
1012 public void onNothingSelected(AdapterView<?> parent) {
1017 // Set the `pinnedSSLCertificateSwitch` `onCheckedChangeListener()`.
1018 pinnedSslCertificateSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
1020 public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
1022 if (isChecked) { // Pinned SSL certificate is enabled.
1023 // Set the icon according to the theme.
1024 if (MainWebViewActivity.darkTheme) {
1025 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_dark));
1027 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_light));
1030 // Update the visibility of the saved SSL certificate.
1031 if (savedSslCertificateIssuedToCNameString == null) {
1032 savedSslCertificateLinearLayout.setVisibility(View.GONE);
1034 savedSslCertificateLinearLayout.setVisibility(View.VISIBLE);
1037 // Update the visibility of the current website SSL certificate.
1038 if (currentWebsiteSslCertificate == null) {
1039 // Hide the SSL certificate.
1040 currentWebsiteCertificateLinearLayout.setVisibility(View.GONE);
1042 // Show the instruction.
1043 noCurrentWebsiteCertificateTextView.setVisibility(View.VISIBLE);
1045 // Show the SSL certificate.
1046 currentWebsiteCertificateLinearLayout.setVisibility(View.VISIBLE);
1048 // Hide the instruction.
1049 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
1052 // Set the status of the radio buttons.
1053 if (savedSslCertificateLinearLayout.getVisibility() == View.VISIBLE) { // The saved SSL certificate is displayed.
1054 savedSslCertificateRadioButton.setChecked(true);
1055 currentWebsiteCertificateRadioButton.setChecked(false);
1056 } else if (currentWebsiteCertificateLinearLayout.getVisibility() == View.VISIBLE) { // The saved SSL certificate is hidden but the current website SSL certificate is visible.
1057 currentWebsiteCertificateRadioButton.setChecked(true);
1058 savedSslCertificateRadioButton.setChecked(false);
1059 } else { // Neither SSL certificate is visible.
1060 savedSslCertificateRadioButton.setChecked(false);
1061 currentWebsiteCertificateRadioButton.setChecked(false);
1063 } else { // Pinned SSL certificate is disabled.
1064 // Set the icon according to the theme.
1065 if (MainWebViewActivity.darkTheme) {
1066 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_dark));
1068 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_light));
1071 // Hide the SSl certificates and instructions.
1072 savedSslCertificateLinearLayout.setVisibility(View.GONE);
1073 currentWebsiteCertificateLinearLayout.setVisibility(View.GONE);
1074 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
1076 // Uncheck the radio buttons.
1077 savedSslCertificateRadioButton.setChecked(false);
1078 currentWebsiteCertificateRadioButton.setChecked(false);
1083 savedSslCertificateLinearLayout.setOnClickListener(new View.OnClickListener() {
1085 public void onClick(View v) {
1086 savedSslCertificateRadioButton.setChecked(true);
1087 currentWebsiteCertificateRadioButton.setChecked(false);
1091 savedSslCertificateRadioButton.setOnClickListener(new View.OnClickListener() {
1093 public void onClick(View v) {
1094 savedSslCertificateRadioButton.setChecked(true);
1095 currentWebsiteCertificateRadioButton.setChecked(false);
1099 currentWebsiteCertificateLinearLayout.setOnClickListener(new View.OnClickListener() {
1101 public void onClick(View v) {
1102 currentWebsiteCertificateRadioButton.setChecked(true);
1103 savedSslCertificateRadioButton.setChecked(false);
1107 currentWebsiteCertificateRadioButton.setOnClickListener(new View.OnClickListener() {
1109 public void onClick(View v) {
1110 currentWebsiteCertificateRadioButton.setChecked(true);
1111 savedSslCertificateRadioButton.setChecked(false);
1115 return domainSettingsView;
1118 private boolean checkDomainNameAgainstCertificate(String domainName, String certificateCommonName) {
1119 // Initialize `domainNamesMatch`.
1120 boolean domainNamesMatch = false;
1122 // Check if the domains match.
1123 if (domainName.equals(certificateCommonName)) {
1124 domainNamesMatch = true;
1127 // Check various wildcard permutations if `domainName` and `certificateCommonName` are not empty. `noinspection ConstantCondition` removes Android Studio's incorrect lint warning that `domainName` can never be `null`.
1128 //noinspection ConstantConditions
1129 if ((domainName != null) && (certificateCommonName != null)) {
1130 // If `domainName` starts with a wildcard, check the base domain against all the subdomains of `certificateCommonName`.
1131 if (!domainNamesMatch && domainName.startsWith("*.") && (domainName.length() > 2)) {
1132 // Remove the initial `*.`.
1133 String baseDomainName = domainName.substring(2);
1135 // Setup a copy of `certificateCommonName` to test subdomains.
1136 String certificateCommonNameSubdomain = certificateCommonName;
1138 // Check all the subdomains in `certificateCommonNameSubdomains` against `baseDomainName`.
1139 while (!domainNamesMatch && certificateCommonNameSubdomain.contains(".")) { // Stop checking if we know that `domainNamesMatch` is `true` or if we run out of `.`.
1140 // Test the `certificateCommonNameSubdomain` against `baseDomainName`.
1141 if (certificateCommonNameSubdomain.equals(baseDomainName)) {
1142 domainNamesMatch = true;
1145 // Strip out the lowest subdomain of `certificateCommonNameSubdomain`.
1147 certificateCommonNameSubdomain = certificateCommonNameSubdomain.substring(certificateCommonNameSubdomain.indexOf(".") + 1);
1148 } catch (IndexOutOfBoundsException e) { // `certificateCommonNameSubdomain` ends with `.`.
1149 certificateCommonNameSubdomain = "";
1154 // If `certificateCommonName` starts with a wildcard, check the base common name against all the subdomains of `domainName`.
1155 if (!domainNamesMatch && certificateCommonName.startsWith("*.") && (certificateCommonName.length() > 2)) {
1156 // Remove the initial `*.`.
1157 String baseCertificateCommonName = certificateCommonName.substring(2);
1159 // Setup a copy of `domainName` to test subdomains.
1160 String domainNameSubdomain = domainName;
1162 // Check all the subdomains in `domainNameSubdomain` against `baseCertificateCommonName`.
1163 while (!domainNamesMatch && domainNameSubdomain.contains(".") && (domainNameSubdomain.length() > 2)) {
1164 // Test the `domainNameSubdomain` against `baseCertificateCommonName`.
1165 if (domainNameSubdomain.equals(baseCertificateCommonName)) {
1166 domainNamesMatch = true;
1169 // Strip out the lowest subdomain of `domainNameSubdomain`.
1171 domainNameSubdomain = domainNameSubdomain.substring(domainNameSubdomain.indexOf(".") + 1);
1172 } catch (IndexOutOfBoundsException e) { // `domainNameSubdomain` ends with `.`.
1173 domainNameSubdomain = "";
1178 // If both names start with a wildcard, check if the root of one contains the root of the other.
1179 if (!domainNamesMatch && domainName.startsWith("*.") && (domainName.length() > 2) && certificateCommonName.startsWith("*.") && (certificateCommonName.length() > 2)) {
1180 // Remove the wildcards.
1181 String rootDomainName = domainName.substring(2);
1182 String rootCertificateCommonName = certificateCommonName.substring(2);
1184 // Check if one name ends with the contents of the other. If so, there will be overlap in the their wildcard subdomains.
1185 if (rootDomainName.endsWith(rootCertificateCommonName) || rootCertificateCommonName.endsWith(rootDomainName)) {
1186 domainNamesMatch = true;
1191 return domainNamesMatch;