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 settings.
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 final boolean defaultDisplayWebpageImagesBoolean = sharedPreferences.getBoolean("display_website_images", true);
95 final boolean defaultNightModeBoolean = sharedPreferences.getBoolean("night_mode", false);
97 // Get handles for the views in the fragment.
98 final EditText domainNameEditText = (EditText) domainSettingsView.findViewById(R.id.domain_settings_name_edittext);
99 final Switch javaScriptEnabledSwitch = (Switch) domainSettingsView.findViewById(R.id.domain_settings_javascript_switch);
100 final ImageView javaScriptImageView = (ImageView) domainSettingsView.findViewById(R.id.domain_settings_javascript_imageview);
101 Switch firstPartyCookiesEnabledSwitch = (Switch) domainSettingsView.findViewById(R.id.domain_settings_first_party_cookies_switch);
102 final ImageView firstPartyCookiesImageView = (ImageView) domainSettingsView.findViewById(R.id.domain_settings_first_party_cookies_imageview);
103 LinearLayout thirdPartyCookiesLinearLayout = (LinearLayout) domainSettingsView.findViewById(R.id.domain_settings_third_party_cookies_linearlayout);
104 final Switch thirdPartyCookiesEnabledSwitch = (Switch) domainSettingsView.findViewById(R.id.domain_settings_third_party_cookies_switch);
105 final ImageView thirdPartyCookiesImageView = (ImageView) domainSettingsView.findViewById(R.id.domain_settings_third_party_cookies_imageview);
106 final Switch domStorageEnabledSwitch = (Switch) domainSettingsView.findViewById(R.id.domain_settings_dom_storage_switch);
107 final ImageView domStorageImageView = (ImageView) domainSettingsView.findViewById(R.id.domain_settings_dom_storage_imageview);
108 Switch formDataEnabledSwitch = (Switch) domainSettingsView.findViewById(R.id.domain_settings_form_data_switch);
109 final ImageView formDataImageView = (ImageView) domainSettingsView.findViewById(R.id.domain_settings_form_data_imageview);
110 final Spinner userAgentSpinner = (Spinner) domainSettingsView.findViewById(R.id.domain_settings_user_agent_spinner);
111 final TextView userAgentTextView = (TextView) domainSettingsView.findViewById(R.id.domain_settings_user_agent_textview);
112 final EditText customUserAgentEditText = (EditText) domainSettingsView.findViewById(R.id.domain_settings_custom_user_agent_edittext);
113 final Spinner fontSizeSpinner = (Spinner) domainSettingsView.findViewById(R.id.domain_settings_font_size_spinner);
114 final TextView fontSizeTextView = (TextView) domainSettingsView.findViewById(R.id.domain_settings_font_size_textview);
115 final ImageView displayWebpageImagesImageView = (ImageView) domainSettingsView.findViewById(R.id.domain_settings_display_webpage_images_imageview);
116 final Spinner displayWebpageImagesSpinner = (Spinner) domainSettingsView.findViewById(R.id.domain_settings_display_webpage_images_spinner);
117 final TextView displayImagesTextView = (TextView) domainSettingsView.findViewById(R.id.domain_settings_display_webpage_images_textview);
118 final ImageView nightModeImageView = (ImageView) domainSettingsView.findViewById(R.id.domain_settings_night_mode_imageview);
119 final Spinner nightModeSpinner = (Spinner) domainSettingsView.findViewById(R.id.domain_settings_night_mode_spinner);
120 final TextView nightModeTextView = (TextView) domainSettingsView.findViewById(R.id.domain_settings_night_mode_textview);
121 final ImageView pinnedSslCertificateImageView = (ImageView) domainSettingsView.findViewById(R.id.domain_settings_pinned_ssl_certificate_imageview);
122 Switch pinnedSslCertificateSwitch = (Switch) domainSettingsView.findViewById(R.id.domain_settings_pinned_ssl_certificate_switch);
123 final LinearLayout savedSslCertificateLinearLayout = (LinearLayout) domainSettingsView.findViewById(R.id.saved_ssl_certificate_linearlayout);
124 final RadioButton savedSslCertificateRadioButton = (RadioButton) domainSettingsView.findViewById(R.id.saved_ssl_certificate_radiobutton);
125 final TextView savedSslCertificateIssuedToCNameTextView = (TextView) domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_to_cname);
126 TextView savedSslCertificateIssuedToONameTextView = (TextView) domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_to_oname);
127 TextView savedSslCertificateIssuedToUNameTextView = (TextView) domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_to_uname);
128 TextView savedSslCertificateIssuedByCNameTextView = (TextView) domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_by_cname);
129 TextView savedSslCertificateIssuedByONameTextView = (TextView) domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_by_oname);
130 TextView savedSslCertificateIssuedByUNameTextView = (TextView) domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_by_uname);
131 TextView savedSslCertificateStartDateTextView = (TextView) domainSettingsView.findViewById(R.id.saved_ssl_certificate_start_date);
132 TextView savedSslCertificateEndDateTextView = (TextView) domainSettingsView.findViewById(R.id.saved_ssl_certificate_end_date);
133 final LinearLayout currentWebsiteCertificateLinearLayout = (LinearLayout) domainSettingsView.findViewById(R.id.current_website_certificate_linearlayout);
134 final RadioButton currentWebsiteCertificateRadioButton = (RadioButton) domainSettingsView.findViewById(R.id.current_website_certificate_radiobutton);
135 final TextView currentWebsiteCertificateIssuedToCNameTextView = (TextView) domainSettingsView.findViewById(R.id.current_website_certificate_issued_to_cname);
136 TextView currentWebsiteCertificateIssuedToONameTextView = (TextView) domainSettingsView.findViewById(R.id.current_website_certificate_issued_to_oname);
137 TextView currentWebsiteCertificateIssuedToUNameTextView = (TextView) domainSettingsView.findViewById(R.id.current_website_certificate_issued_to_uname);
138 TextView currentWebsiteCertificateIssuedByCNameTextView = (TextView) domainSettingsView.findViewById(R.id.current_website_certificate_issued_by_cname);
139 TextView currentWebsiteCertificateIssuedByONameTextView = (TextView) domainSettingsView.findViewById(R.id.current_website_certificate_issued_by_oname);
140 TextView currentWebsiteCertificateIssuedByUNameTextView = (TextView) domainSettingsView.findViewById(R.id.current_website_certificate_issued_by_uname);
141 TextView currentWebsiteCertificateStartDateTextView = (TextView) domainSettingsView.findViewById(R.id.current_website_certificate_start_date);
142 TextView currentWebsiteCertificateEndDateTextView = (TextView) domainSettingsView.findViewById(R.id.current_website_certificate_end_date);
143 final TextView noCurrentWebsiteCertificateTextView = (TextView) domainSettingsView.findViewById(R.id.no_current_website_certificate);
145 // Setup the SSL certificate labels.
146 final String cNameLabel = getString(R.string.common_name) + " ";
147 String oNameLabel = getString(R.string.organization) + " ";
148 String uNameLabel = getString(R.string.organizational_unit) + " ";
149 String startDateLabel = getString(R.string.start_date) + " ";
150 String endDateLabel = getString(R.string.end_date) + " ";
152 // Get the current website SSL certificate
153 final SslCertificate currentWebsiteSslCertificate = MainWebViewActivity.sslCertificate;
155 // 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`.
156 DomainsDatabaseHelper domainsDatabaseHelper = new DomainsDatabaseHelper(context, null, null, 0);
158 // Get the database `Cursor` for this ID and move it to the first row.
159 Cursor domainCursor = domainsDatabaseHelper.getCursorForId(databaseId);
160 domainCursor.moveToFirst();
162 // Save the `Cursor` entries as variables.
163 String domainNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.DOMAIN_NAME));
164 final int javaScriptEnabledInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_JAVASCRIPT));
165 int firstPartyCookiesEnabledInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FIRST_PARTY_COOKIES));
166 int thirdPartyCookiesEnabledInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_THIRD_PARTY_COOKIES));
167 final int domStorageEnabledInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_DOM_STORAGE));
168 int formDataEnabledInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FORM_DATA));
169 final String currentUserAgentString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.USER_AGENT));
170 int fontSizeInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.FONT_SIZE));
171 int displayImagesInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.DISPLAY_IMAGES));
172 int nightModeInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.NIGHT_MODE));
173 int pinnedSslCertificateInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.PINNED_SSL_CERTIFICATE));
174 final String savedSslCertificateIssuedToCNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_TO_COMMON_NAME));
175 String savedSslCertificateIssuedToONameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_TO_ORGANIZATION));
176 String savedSslCertificateIssuedToUNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_TO_ORGANIZATIONAL_UNIT));
177 String savedSslCertificateIssuedByCNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_BY_COMMON_NAME));
178 String savedSslCertificateIssuedByONameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_BY_ORGANIZATION));
179 String savedSslCertificateIssuedByUNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_BY_ORGANIZATIONAL_UNIT));
181 // Initialize the saved SSL certificate date variables.
182 Date savedSslCertificateStartDate = null;
183 Date savedSslCertificateEndDate = null;
185 // Only get the saved SSL certificate dates from the cursor if they are not set to `0`.
186 if (domainCursor.getLong(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_START_DATE)) != 0) {
187 savedSslCertificateStartDate = new Date(domainCursor.getLong(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_START_DATE)));
190 if (domainCursor.getLong(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_END_DATE)) != 0) {
191 savedSslCertificateEndDate = new Date(domainCursor.getLong(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_END_DATE)));
194 // Create `ArrayAdapters` for the `Spinners`and their `entry values`.
195 ArrayAdapter<CharSequence> userAgentArrayAdapter = ArrayAdapter.createFromResource(context, R.array.domain_settings_user_agent_entries, R.layout.spinner_item);
196 final ArrayAdapter<CharSequence> userAgentEntryValuesArrayAdapter = ArrayAdapter.createFromResource(context, R.array.domain_settings_user_agent_entry_values, R.layout.spinner_item);
197 ArrayAdapter<CharSequence> fontSizeArrayAdapter = ArrayAdapter.createFromResource(context, R.array.domain_settings_font_size_entries, R.layout.spinner_item);
198 ArrayAdapter<CharSequence> fontSizeEntryValuesArrayAdapter = ArrayAdapter.createFromResource(context, R.array.domain_settings_font_size_entry_values, R.layout.spinner_item);
199 final ArrayAdapter<CharSequence> displayImagesArrayAdapter = ArrayAdapter.createFromResource(context, R.array.display_webpage_images_array, R.layout.spinner_item);
200 ArrayAdapter<CharSequence> nightModeArrayAdapter = ArrayAdapter.createFromResource(context, R.array.night_mode_array, R.layout.spinner_item);
202 // Set the `DropDownViewResource` on the `Spinners`.
203 userAgentArrayAdapter.setDropDownViewResource(R.layout.spinner_dropdown_item);
204 fontSizeArrayAdapter.setDropDownViewResource(R.layout.spinner_dropdown_item);
205 displayImagesArrayAdapter.setDropDownViewResource(R.layout.spinner_dropdown_item);
206 nightModeArrayAdapter.setDropDownViewResource(R.layout.spinner_dropdown_item);
208 // Set the `ArrayAdapters` for the `Spinners`.
209 userAgentSpinner.setAdapter(userAgentArrayAdapter);
210 fontSizeSpinner.setAdapter(fontSizeArrayAdapter);
211 displayWebpageImagesSpinner.setAdapter(displayImagesArrayAdapter);
212 nightModeSpinner.setAdapter(nightModeArrayAdapter);
214 // Create a `SpannableStringBuilder` for each `TextView` that needs multiple colors of text.
215 SpannableStringBuilder savedSslCertificateIssuedToCNameStringBuilder = new SpannableStringBuilder(cNameLabel + savedSslCertificateIssuedToCNameString);
216 SpannableStringBuilder savedSslCertificateIssuedToONameStringBuilder = new SpannableStringBuilder(oNameLabel + savedSslCertificateIssuedToONameString);
217 SpannableStringBuilder savedSslCertificateIssuedToUNameStringBuilder = new SpannableStringBuilder(uNameLabel + savedSslCertificateIssuedToUNameString);
218 SpannableStringBuilder savedSslCertificateIssuedByCNameStringBuilder = new SpannableStringBuilder(cNameLabel + savedSslCertificateIssuedByCNameString);
219 SpannableStringBuilder savedSslCertificateIssuedByONameStringBuilder = new SpannableStringBuilder(oNameLabel + savedSslCertificateIssuedByONameString);
220 SpannableStringBuilder savedSslCertificateIssuedByUNameStringBuilder = new SpannableStringBuilder(uNameLabel + savedSslCertificateIssuedByUNameString);
222 // Initialize the `SpannableStringBuilders` for the SSL certificate dates.
223 SpannableStringBuilder savedSslCertificateStartDateStringBuilder;
224 SpannableStringBuilder savedSslCertificateEndDateStringBuilder;
226 // Leave the SSL certificate dates empty if they are `null`.
227 if (savedSslCertificateStartDate == null) {
228 savedSslCertificateStartDateStringBuilder = new SpannableStringBuilder(startDateLabel);
230 savedSslCertificateStartDateStringBuilder = new SpannableStringBuilder(startDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(savedSslCertificateStartDate));
233 if (savedSslCertificateEndDate == null) {
234 savedSslCertificateEndDateStringBuilder = new SpannableStringBuilder(endDateLabel);
236 savedSslCertificateEndDateStringBuilder = new SpannableStringBuilder(endDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(savedSslCertificateEndDate));
239 // Create a red `ForegroundColorSpan`. We have to use the deprecated `getColor` until API >= 23.
240 final ForegroundColorSpan redColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.red_a700));
242 // Create a blue `ForegroundColorSpan`.
243 final ForegroundColorSpan blueColorSpan;
245 // Set `blueColorSpan` according to the theme. We have to use the deprecated `getColor()` until API >= 23.
246 if (MainWebViewActivity.darkTheme) {
247 //noinspection deprecation
248 blueColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.blue_400));
250 //noinspection deprecation
251 blueColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.blue_700));
254 // Set the domain name from the the database cursor.
255 domainNameEditText.setText(domainNameString);
257 // Update the certificates' `Common Name` color when the domain name text changes.
258 domainNameEditText.addTextChangedListener(new TextWatcher() {
260 public void beforeTextChanged(CharSequence s, int start, int count, int after) {
265 public void onTextChanged(CharSequence s, int start, int before, int count) {
270 public void afterTextChanged(Editable s) {
271 // Get the new domain name.
272 String newDomainName = domainNameEditText.getText().toString();
274 // Check the saved SSL certificate against the new domain name.
275 boolean savedSslCertificateMatchesNewDomainName = checkDomainNameAgainstCertificate(newDomainName, savedSslCertificateIssuedToCNameString);
277 // Create a `SpannableStringBuilder` for the saved certificate `Common Name`.
278 SpannableStringBuilder savedSslCertificateCommonNameStringBuilder = new SpannableStringBuilder(cNameLabel + savedSslCertificateIssuedToCNameString);
280 // Format the saved certificate `Common Name` color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
281 if (savedSslCertificateMatchesNewDomainName) {
282 savedSslCertificateCommonNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), savedSslCertificateCommonNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
284 savedSslCertificateCommonNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), savedSslCertificateCommonNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
287 // Update `savedSslCertificateIssuedToCNameTextView`.
288 savedSslCertificateIssuedToCNameTextView.setText(savedSslCertificateCommonNameStringBuilder);
290 // Update the current website certificate if it exists.
291 if (currentWebsiteSslCertificate != null) {
292 // Get the current website certificate `Common Name`.
293 String currentWebsiteCertificateCommonName = currentWebsiteSslCertificate.getIssuedTo().getCName();
295 // Check the current website certificate against the new domain name.
296 boolean currentWebsiteCertificateMatchesNewDomainName = checkDomainNameAgainstCertificate(newDomainName, currentWebsiteCertificateCommonName);
298 // Create a `SpannableStringBuilder` for the current website certificate `Common Name`.
299 SpannableStringBuilder currentWebsiteCertificateCommonNameStringBuilder = new SpannableStringBuilder(cNameLabel + currentWebsiteCertificateCommonName);
301 // Format the current certificate `Common Name` color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
302 if (currentWebsiteCertificateMatchesNewDomainName) {
303 currentWebsiteCertificateCommonNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), currentWebsiteCertificateCommonNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
305 currentWebsiteCertificateCommonNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), currentWebsiteCertificateCommonNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
308 // Update `currentWebsiteCertificateIssuedToCNameTextView`.
309 currentWebsiteCertificateIssuedToCNameTextView.setText(currentWebsiteCertificateCommonNameStringBuilder);
314 // Create a `boolean` to track if night mode is enabled.
315 boolean nightModeEnabled = (nightModeInt == DomainsDatabaseHelper.NIGHT_MODE_ENABLED) || ((nightModeInt == DomainsDatabaseHelper.NIGHT_MODE_SYSTEM_DEFAULT) && defaultNightModeBoolean);
317 // Disable the JavaScript `Switch` if night mode is enabled.
318 if (nightModeEnabled) {
319 javaScriptEnabledSwitch.setEnabled(false);
321 javaScriptEnabledSwitch.setEnabled(true);
324 // Set the JavaScript icon.
325 if ((javaScriptEnabledInt == 1) || nightModeEnabled) {
326 javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.javascript_enabled));
328 javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.privacy_mode));
331 // Set the JavaScript `Switch` status.
332 if (javaScriptEnabledInt == 1) { // JavaScript is enabled.
333 javaScriptEnabledSwitch.setChecked(true);
334 } else { // JavaScript is disabled.
335 javaScriptEnabledSwitch.setChecked(false);
338 // Set the first-party cookies status. Once minimum API >= 21 we can use a selector as the tint mode instead of specifying different icons.
339 if (firstPartyCookiesEnabledInt == 1) { // First-party cookies are enabled.
340 firstPartyCookiesEnabledSwitch.setChecked(true);
341 firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_enabled));
342 } else { // First-party cookies are disabled.
343 firstPartyCookiesEnabledSwitch.setChecked(false);
345 // Set the icon according to the theme.
346 if (MainWebViewActivity.darkTheme) {
347 firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_dark));
349 firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_light));
353 // Only display third-party cookies if SDK_INT >= 21.
354 if (Build.VERSION.SDK_INT >= 21) { // Third-party cookies can be configured for API >= 21.
355 // Only enable third-party-cookies if first-party cookies are enabled.
356 if (firstPartyCookiesEnabledInt == 1) { // First-party cookies are enabled.
357 // Set the third-party cookies status. Once minimum API >= 21 we can use a selector as the tint mode instead of specifying different icons.
358 if (thirdPartyCookiesEnabledInt == 1) { // Both first-party and third-party cookies are enabled.
359 thirdPartyCookiesEnabledSwitch.setChecked(true);
360 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_warning));
361 } else { // First party cookies are enabled but third-party cookies are disabled.
362 thirdPartyCookiesEnabledSwitch.setChecked(false);
364 // Set the icon according to the theme.
365 if (MainWebViewActivity.darkTheme) {
366 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_dark));
368 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_light));
371 } else { // First-party cookies are disabled.
372 // Set the status of third-party cookies.
373 if (thirdPartyCookiesEnabledInt == 1) {
374 thirdPartyCookiesEnabledSwitch.setChecked(true);
376 thirdPartyCookiesEnabledSwitch.setChecked(false);
379 // Disable the third-party cookies switch.
380 thirdPartyCookiesEnabledSwitch.setEnabled(false);
382 // Set the icon according to the theme.
383 if (MainWebViewActivity.darkTheme) {
384 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_ghosted_dark));
386 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_ghosted_light));
389 } else { // Third-party cookies cannot be configured for API <= 21.
390 // Hide the `LinearLayout` for third-party cookies.
391 thirdPartyCookiesLinearLayout.setVisibility(View.GONE);
394 // Only enable DOM storage if JavaScript is enabled.
395 if ((javaScriptEnabledInt == 1) || nightModeEnabled) { // JavaScript is enabled.
396 // Enable the DOM storage `Switch`.
397 domStorageEnabledSwitch.setEnabled(true);
399 // Set the DOM storage status. Once minimum API >= 21 we can use a selector as the tint mode instead of specifying different icons.
400 if (domStorageEnabledInt == 1) { // Both JavaScript and DOM storage are enabled.
401 domStorageEnabledSwitch.setChecked(true);
402 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_enabled));
403 } else { // JavaScript is enabled but DOM storage is disabled.
404 // Set the DOM storage switch to off.
405 domStorageEnabledSwitch.setChecked(false);
407 // Set the icon according to the theme.
408 if (MainWebViewActivity.darkTheme) {
409 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_dark));
411 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_light));
414 } else { // JavaScript is disabled.
415 // Disable the DOM storage `Switch`.
416 domStorageEnabledSwitch.setEnabled(false);
418 // Set the checked status of DOM storage.
419 if (domStorageEnabledInt == 1) { // DOM storage is enabled but JavaScript is disabled.
420 domStorageEnabledSwitch.setChecked(true);
421 } else { // Both JavaScript and DOM storage are disabled.
422 domStorageEnabledSwitch.setChecked(false);
425 // Set the icon according to the theme.
426 if (MainWebViewActivity.darkTheme) {
427 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_dark));
429 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_light));
433 // Set the form data status. Once minimum API >= 21 we can use a selector as the tint mode instead of specifying different icons.
434 if (formDataEnabledInt == 1) { // Form data is enabled.
435 formDataEnabledSwitch.setChecked(true);
436 formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_enabled));
437 } else { // Form data is disabled.
438 // Set the form data switch to off.
439 formDataEnabledSwitch.setChecked(false);
441 // Set the icon according to the theme.
442 if (MainWebViewActivity.darkTheme) {
443 formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_disabled_dark));
445 formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_disabled_light));
449 // We need to inflated a `WebView` to get the default user agent.
450 // `@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.
451 @SuppressLint("InflateParams") View bareWebViewLayout = inflater.inflate(R.layout.bare_webview, null, false);
452 WebView bareWebView = (WebView) bareWebViewLayout.findViewById(R.id.bare_webview);
453 final String webViewDefaultUserAgentString = bareWebView.getSettings().getUserAgentString();
455 // Get the position of the user agent in `userAgentEntryValuesArrayAdapter`.
456 int userAgentArrayPosition = userAgentEntryValuesArrayAdapter.getPosition(currentUserAgentString);
458 // Set the user agent.
459 if (userAgentArrayPosition == -1) { // We are using a custom `userAgentString`.
460 // Set `userAgentSpinner` to `Custom`.
461 userAgentSpinner.setSelection(userAgentEntryValuesArrayAdapter.getPosition("Custom user agent"));
463 // Hide `userAgentTextView`.
464 userAgentTextView.setVisibility(View.GONE);
466 // Show `customUserAgentEditText` and set `userAgentString` as the text.
467 customUserAgentEditText.setVisibility(View.VISIBLE);
468 customUserAgentEditText.setText(currentUserAgentString);
469 } else{ // We are using one of the preset user agents.
470 // Set the `userAgentSpinner` selection.
471 userAgentSpinner.setSelection(userAgentArrayPosition);
473 // Show `userAgentTextView`.
474 userAgentTextView.setVisibility(View.VISIBLE);
476 // Hide `customUserAgentEditText`.
477 customUserAgentEditText.setVisibility(View.GONE);
479 // Set the user agent text.
480 switch (currentUserAgentString) {
481 case "System default user agent":
482 // Display the user agent text string.
483 switch (defaultUserAgentString) {
484 case "WebView default user agent":
485 // Display the `WebView` default user agent.
486 userAgentTextView.setText(webViewDefaultUserAgentString);
489 case "Custom user agent":
490 // Display the custom user agent.
491 userAgentTextView.setText(defaultCustomUserAgentString);
495 // Display the text from `defaultUserAgentString`.
496 userAgentTextView.setText(defaultUserAgentString);
500 case "WebView default user agent":
501 // Display the `WebView` default user agent.
502 userAgentTextView.setText(webViewDefaultUserAgentString);
506 // Display the text from `currentUserAgentString`.
507 userAgentTextView.setText(currentUserAgentString);
511 // Open the user agent spinner when the `TextView` is clicked.
512 userAgentTextView.setOnClickListener(new View.OnClickListener() {
514 public void onClick(View v) {
515 // Open the user agent spinner.
516 userAgentSpinner.performClick();
520 // Set the selected font size.
521 int fontSizeArrayPosition = fontSizeEntryValuesArrayAdapter.getPosition(String.valueOf(fontSizeInt));
522 fontSizeSpinner.setSelection(fontSizeArrayPosition);
524 // Set the default font size text.
525 int defaultFontSizeArrayPosition = fontSizeEntryValuesArrayAdapter.getPosition(defaultFontSizeString);
526 fontSizeTextView.setText(fontSizeArrayAdapter.getItem(defaultFontSizeArrayPosition));
528 // Set the display options for `fontSizeTextView`.
529 if (fontSizeArrayPosition == 0) { // System default font size is selected. Display `fontSizeTextView`.
530 fontSizeTextView.setVisibility(View.VISIBLE);
531 } else { // A custom font size is specified. Hide `fontSizeTextView`.
532 fontSizeTextView.setVisibility(View.GONE);
535 // Open the font size spinner when the `TextView` is clicked.
536 fontSizeTextView.setOnClickListener(new View.OnClickListener() {
538 public void onClick(View v) {
539 // Open the user agent spinner.
540 fontSizeSpinner.performClick();
544 // Display the website images mode in the spinner.
545 displayWebpageImagesSpinner.setSelection(displayImagesInt);
547 // Set the default display images text.
548 if (defaultDisplayWebpageImagesBoolean) {
549 displayImagesTextView.setText(displayImagesArrayAdapter.getItem(DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_ENABLED));
551 displayImagesTextView.setText(displayImagesArrayAdapter.getItem(DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_DISABLED));
554 // Set the display website images icon and `TextView` settings. Once minimum API >= 21 we can use a selector as the tint mode instead of specifying different icons.
555 switch (displayImagesInt) {
556 case DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_SYSTEM_DEFAULT:
557 if (defaultDisplayWebpageImagesBoolean) { // Display webpage images enabled by default.
558 // Set the icon according to the theme.
559 if (MainWebViewActivity.darkTheme) {
560 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_dark));
562 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_light));
564 } else { // Display webpage images disabled by default.
565 // Set the icon according to the theme.
566 if (MainWebViewActivity.darkTheme) {
567 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_dark));
569 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_light));
573 // Show `displayImagesTextView`.
574 displayImagesTextView.setVisibility(View.VISIBLE);
577 case DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_ENABLED:
578 // Set the icon according to the theme.
579 if (MainWebViewActivity.darkTheme) {
580 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_dark));
582 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_light));
585 // Hide `displayImagesTextView`.
586 displayImagesTextView.setVisibility(View.GONE);
589 case DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_DISABLED:
590 // Set the icon according to the theme.
591 if (MainWebViewActivity.darkTheme) {
592 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_dark));
594 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_light));
597 // Hide `displayImagesTextView`.
598 displayImagesTextView.setVisibility(View.GONE);
602 // Open the display images spinner when the `TextView` is clicked.
603 displayImagesTextView.setOnClickListener(new View.OnClickListener() {
605 public void onClick(View v) {
606 // Open the user agent spinner.
607 displayWebpageImagesSpinner.performClick();
611 // Display the night mode in the spinner.
612 nightModeSpinner.setSelection(nightModeInt);
614 // Set the default night mode text.
615 if (defaultNightModeBoolean) {
616 nightModeTextView.setText(nightModeArrayAdapter.getItem(DomainsDatabaseHelper.NIGHT_MODE_ENABLED));
618 nightModeTextView.setText(nightModeArrayAdapter.getItem(DomainsDatabaseHelper.NIGHT_MODE_DISABLED));
621 // Set the night mode icon and `TextView` settings. Once minimum API >= 21 we can use a selector as the tint mode instead of specifying different icons.
622 switch (displayImagesInt) {
623 case DomainsDatabaseHelper.NIGHT_MODE_SYSTEM_DEFAULT:
624 if (defaultNightModeBoolean) { // Night mode enabled by default.
625 // Set the icon according to the theme.
626 if (MainWebViewActivity.darkTheme) {
627 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_dark));
629 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_light));
631 } else { // Night mode disabled by default.
632 // Set the icon according to the theme.
633 if (MainWebViewActivity.darkTheme) {
634 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_dark));
636 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_light));
640 // Show `nightModeTextView`.
641 nightModeTextView.setVisibility(View.VISIBLE);
644 case DomainsDatabaseHelper.NIGHT_MODE_ENABLED:
645 // Set the icon according to the theme.
646 if (MainWebViewActivity.darkTheme) {
647 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_dark));
649 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_light));
652 // Hide `nightModeTextView`.
653 nightModeTextView.setVisibility(View.GONE);
656 case DomainsDatabaseHelper.NIGHT_MODE_DISABLED:
657 // Set the icon according to the theme.
658 if (MainWebViewActivity.darkTheme) {
659 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_dark));
661 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_light));
664 // Hide `nightModeTextView`.
665 nightModeTextView.setVisibility(View.GONE);
669 // Open the night mode spinner when the `TextView` is clicked.
670 nightModeTextView.setOnClickListener(new View.OnClickListener() {
672 public void onClick(View v) {
673 // Open the user agent spinner.
674 nightModeSpinner.performClick();
678 // Set the pinned SSL certificate icon.
679 if (pinnedSslCertificateInt == 1) { // Pinned SSL certificate is enabled. Once minimum API >= 21 we can use a selector as the tint mode instead of specifying different icons.
681 pinnedSslCertificateSwitch.setChecked(true);
683 // Set the icon according to the theme.
684 if (MainWebViewActivity.darkTheme) {
685 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_dark));
687 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_light));
689 } else { // Pinned SSL certificate is disabled.
690 // Uncheck the switch.
691 pinnedSslCertificateSwitch.setChecked(false);
693 // Set the icon according to the theme.
694 if (MainWebViewActivity.darkTheme) {
695 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_dark));
697 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_light));
701 // Store the current date.
702 Date currentDate = Calendar.getInstance().getTime();
704 // Setup the `StringBuilders` to display the general certificate information in blue. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
705 savedSslCertificateIssuedToONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), savedSslCertificateIssuedToONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
706 savedSslCertificateIssuedToUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), savedSslCertificateIssuedToUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
707 savedSslCertificateIssuedByCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), savedSslCertificateIssuedByCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
708 savedSslCertificateIssuedByONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), savedSslCertificateIssuedByONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
709 savedSslCertificateIssuedByUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), savedSslCertificateIssuedByUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
711 // Check the certificate `Common Name` against the domain name.
712 boolean savedSSlCertificateCommonNameMatchesDomainName = checkDomainNameAgainstCertificate(domainNameString, savedSslCertificateIssuedToCNameString);
714 // Format the `issuedToCommonName` color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
715 if (savedSSlCertificateCommonNameMatchesDomainName) {
716 savedSslCertificateIssuedToCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), savedSslCertificateIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
718 savedSslCertificateIssuedToCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), savedSslCertificateIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
721 // Format the start date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
722 if ((savedSslCertificateStartDate != null) && savedSslCertificateStartDate.after(currentDate)) { // The certificate start date is in the future.
723 savedSslCertificateStartDateStringBuilder.setSpan(redColorSpan, startDateLabel.length(), savedSslCertificateStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
724 } else { // The certificate start date is in the past.
725 savedSslCertificateStartDateStringBuilder.setSpan(blueColorSpan, startDateLabel.length(), savedSslCertificateStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
728 // Format the end date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
729 if ((savedSslCertificateEndDate != null) && savedSslCertificateEndDate.before(currentDate)) { // The certificate end date is in the past.
730 savedSslCertificateEndDateStringBuilder.setSpan(redColorSpan, endDateLabel.length(), savedSslCertificateEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
731 } else { // The certificate end date is in the future.
732 savedSslCertificateEndDateStringBuilder.setSpan(blueColorSpan, endDateLabel.length(), savedSslCertificateEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
735 // Display the current website SSL certificate strings.
736 savedSslCertificateIssuedToCNameTextView.setText(savedSslCertificateIssuedToCNameStringBuilder);
737 savedSslCertificateIssuedToONameTextView.setText(savedSslCertificateIssuedToONameStringBuilder);
738 savedSslCertificateIssuedToUNameTextView.setText(savedSslCertificateIssuedToUNameStringBuilder);
739 savedSslCertificateIssuedByCNameTextView.setText(savedSslCertificateIssuedByCNameStringBuilder);
740 savedSslCertificateIssuedByONameTextView.setText(savedSslCertificateIssuedByONameStringBuilder);
741 savedSslCertificateIssuedByUNameTextView.setText(savedSslCertificateIssuedByUNameStringBuilder);
742 savedSslCertificateStartDateTextView.setText(savedSslCertificateStartDateStringBuilder);
743 savedSslCertificateEndDateTextView.setText(savedSslCertificateEndDateStringBuilder);
745 // Populate the current website SSL certificate if there is one.
746 if (currentWebsiteSslCertificate != null) {
747 // Get the strings from the SSL certificate.
748 String currentWebsiteCertificateIssuedToCNameString = currentWebsiteSslCertificate.getIssuedTo().getCName();
749 String currentWebsiteCertificateIssuedToONameString = currentWebsiteSslCertificate.getIssuedTo().getOName();
750 String currentWebsiteCertificateIssuedToUNameString = currentWebsiteSslCertificate.getIssuedTo().getUName();
751 String currentWebsiteCertificateIssuedByCNameString = currentWebsiteSslCertificate.getIssuedBy().getCName();
752 String currentWebsiteCertificateIssuedByONameString = currentWebsiteSslCertificate.getIssuedBy().getOName();
753 String currentWebsiteCertificateIssuedByUNameString = currentWebsiteSslCertificate.getIssuedBy().getUName();
754 Date currentWebsiteCertificateStartDate = currentWebsiteSslCertificate.getValidNotBeforeDate();
755 Date currentWebsiteCertificateEndDate = currentWebsiteSslCertificate.getValidNotAfterDate();
757 // Create a `SpannableStringBuilder` for each `TextView` that needs multiple colors of text.
758 SpannableStringBuilder currentWebsiteCertificateIssuedToCNameStringBuilder = new SpannableStringBuilder(cNameLabel + currentWebsiteCertificateIssuedToCNameString);
759 SpannableStringBuilder currentWebsiteCertificateIssuedToONameStringBuilder = new SpannableStringBuilder(oNameLabel + currentWebsiteCertificateIssuedToONameString);
760 SpannableStringBuilder currentWebsiteCertificateIssuedToUNameStringBuilder = new SpannableStringBuilder(uNameLabel + currentWebsiteCertificateIssuedToUNameString);
761 SpannableStringBuilder currentWebsiteCertificateIssuedByCNameStringBuilder = new SpannableStringBuilder(cNameLabel + currentWebsiteCertificateIssuedByCNameString);
762 SpannableStringBuilder currentWebsiteCertificateIssuedByONameStringBuilder = new SpannableStringBuilder(oNameLabel + currentWebsiteCertificateIssuedByONameString);
763 SpannableStringBuilder currentWebsiteCertificateIssuedByUNameStringBuilder = new SpannableStringBuilder(uNameLabel + currentWebsiteCertificateIssuedByUNameString);
764 SpannableStringBuilder currentWebsiteCertificateStartDateStringBuilder = new SpannableStringBuilder(startDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(currentWebsiteCertificateStartDate));
765 SpannableStringBuilder currentWebsiteCertificateEndDateStringBuilder = new SpannableStringBuilder(endDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(currentWebsiteCertificateEndDate));
767 // Setup the `StringBuilders` to display the general certificate information in blue. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
768 currentWebsiteCertificateIssuedToONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), currentWebsiteCertificateIssuedToONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
769 currentWebsiteCertificateIssuedToUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), currentWebsiteCertificateIssuedToUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
770 currentWebsiteCertificateIssuedByCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), currentWebsiteCertificateIssuedByCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
771 currentWebsiteCertificateIssuedByONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), currentWebsiteCertificateIssuedByONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
772 currentWebsiteCertificateIssuedByUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), currentWebsiteCertificateIssuedByUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
774 // Check the certificate `Common Name` against the domain name.
775 boolean currentWebsiteCertificateCommonNameMatchesDomainName = checkDomainNameAgainstCertificate(domainNameString, currentWebsiteCertificateIssuedToCNameString);
777 // Format the `issuedToCommonName` color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
778 if (currentWebsiteCertificateCommonNameMatchesDomainName) {
779 currentWebsiteCertificateIssuedToCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), currentWebsiteCertificateIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
781 currentWebsiteCertificateIssuedToCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), currentWebsiteCertificateIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
784 // Format the start date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
785 if (currentWebsiteCertificateStartDate.after(currentDate)) { // The certificate start date is in the future.
786 currentWebsiteCertificateStartDateStringBuilder.setSpan(redColorSpan, startDateLabel.length(), currentWebsiteCertificateStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
787 } else { // The certificate start date is in the past.
788 currentWebsiteCertificateStartDateStringBuilder.setSpan(blueColorSpan, startDateLabel.length(), currentWebsiteCertificateStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
791 // Format the end date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
792 if (currentWebsiteCertificateEndDate.before(currentDate)) { // The certificate end date is in the past.
793 currentWebsiteCertificateEndDateStringBuilder.setSpan(redColorSpan, endDateLabel.length(), currentWebsiteCertificateEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
794 } else { // The certificate end date is in the future.
795 currentWebsiteCertificateEndDateStringBuilder.setSpan(blueColorSpan, endDateLabel.length(), currentWebsiteCertificateEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
798 // Display the current website SSL certificate strings.
799 currentWebsiteCertificateIssuedToCNameTextView.setText(currentWebsiteCertificateIssuedToCNameStringBuilder);
800 currentWebsiteCertificateIssuedToONameTextView.setText(currentWebsiteCertificateIssuedToONameStringBuilder);
801 currentWebsiteCertificateIssuedToUNameTextView.setText(currentWebsiteCertificateIssuedToUNameStringBuilder);
802 currentWebsiteCertificateIssuedByCNameTextView.setText(currentWebsiteCertificateIssuedByCNameStringBuilder);
803 currentWebsiteCertificateIssuedByONameTextView.setText(currentWebsiteCertificateIssuedByONameStringBuilder);
804 currentWebsiteCertificateIssuedByUNameTextView.setText(currentWebsiteCertificateIssuedByUNameStringBuilder);
805 currentWebsiteCertificateStartDateTextView.setText(currentWebsiteCertificateStartDateStringBuilder);
806 currentWebsiteCertificateEndDateTextView.setText(currentWebsiteCertificateEndDateStringBuilder);
809 // Set the initial display status for the SSL certificates.
810 if (pinnedSslCertificateSwitch.isChecked()) {
811 // Set the visibility of the saved SSL certificate.
812 if (savedSslCertificateIssuedToCNameString == null) {
813 savedSslCertificateLinearLayout.setVisibility(View.GONE);
815 savedSslCertificateLinearLayout.setVisibility(View.VISIBLE);
818 // Set the visibility of the current website SSL certificate.
819 if (currentWebsiteSslCertificate == null) {
820 // Hide the SSL certificate.
821 currentWebsiteCertificateLinearLayout.setVisibility(View.GONE);
823 // Show the instruction.
824 noCurrentWebsiteCertificateTextView.setVisibility(View.VISIBLE);
826 // Show the SSL certificate.
827 currentWebsiteCertificateLinearLayout.setVisibility(View.VISIBLE);
829 // Hide the instruction.
830 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
833 // Set the status of the radio buttons.
834 if (savedSslCertificateLinearLayout.getVisibility() == View.VISIBLE) { // The saved SSL certificate is displayed.
835 savedSslCertificateRadioButton.setChecked(true);
836 currentWebsiteCertificateRadioButton.setChecked(false);
837 } else if (currentWebsiteCertificateLinearLayout.getVisibility() == View.VISIBLE) { // The saved SSL certificate is hidden but the current website SSL certificate is visible.
838 currentWebsiteCertificateRadioButton.setChecked(true);
839 savedSslCertificateRadioButton.setChecked(false);
840 } else { // Neither SSL certificate is visible.
841 savedSslCertificateRadioButton.setChecked(false);
842 currentWebsiteCertificateRadioButton.setChecked(false);
844 } else { // `pinnedSslCertificateSwitch` is not checked.
845 // Hide the SSl certificates and instructions.
846 savedSslCertificateLinearLayout.setVisibility(View.GONE);
847 currentWebsiteCertificateLinearLayout.setVisibility(View.GONE);
848 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
850 // Uncheck the radio buttons.
851 savedSslCertificateRadioButton.setChecked(false);
852 currentWebsiteCertificateRadioButton.setChecked(false);
856 // Set the `javaScriptEnabledSwitch` `OnCheckedChangeListener()`.
857 javaScriptEnabledSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
859 public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
860 if (isChecked) { // JavaScript is enabled.
861 // Update the JavaScript icon.
862 javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.javascript_enabled));
864 // Enable the DOM storage `Switch`.
865 domStorageEnabledSwitch.setEnabled(true);
867 // Update the DOM storage icon.
868 if (domStorageEnabledSwitch.isChecked()) { // DOM storage is enabled.
869 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_enabled));
870 } else { // DOM storage is disabled.
871 // Set the icon according to the theme.
872 if (MainWebViewActivity.darkTheme) {
873 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_dark));
875 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_light));
878 } else { // JavaScript is disabled.
879 // Update the JavaScript icon.
880 javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.privacy_mode));
882 // Disable the DOM storage `Switch`.
883 domStorageEnabledSwitch.setEnabled(false);
885 // Set the DOM storage icon according to the theme.
886 if (MainWebViewActivity.darkTheme) {
887 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_dark));
889 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_light));
895 // Set the `firstPartyCookiesEnabledSwitch` `OnCheckedChangeListener()`.
896 firstPartyCookiesEnabledSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
898 public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
899 if (isChecked) { // First-party cookies are enabled.
900 // Update the first-party cookies icon.
901 firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_enabled));
903 // Enable the third-party cookies `Switch`.
904 thirdPartyCookiesEnabledSwitch.setEnabled(true);
906 // Update the third-party cookies icon.
907 if (thirdPartyCookiesEnabledSwitch.isChecked()) { // Third-party cookies are enabled.
908 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_warning));
909 } else { // Third-party cookies are disabled.
910 // Set the third-party cookies icon according to the theme.
911 if (MainWebViewActivity.darkTheme) {
912 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_dark));
914 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_light));
917 } else { // First-party cookies are disabled.
918 // Update the first-party cookies icon according to the theme.
919 if (MainWebViewActivity.darkTheme) {
920 firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_dark));
922 firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_light));
925 // Disable the third-party cookies `Switch`.
926 thirdPartyCookiesEnabledSwitch.setEnabled(false);
928 // Set the third-party cookies icon according to the theme.
929 if (MainWebViewActivity.darkTheme) {
930 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_ghosted_dark));
932 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_ghosted_light));
938 // Set the `thirdPartyCookiesEnabledSwitch` `OnCheckedChangeListener()`.
939 thirdPartyCookiesEnabledSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
941 public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
944 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_warning));
946 // Update the third-party cookies icon according to the theme.
947 if (MainWebViewActivity.darkTheme) {
948 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_dark));
950 thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_light));
956 // Set the `domStorageEnabledSwitch` `OnCheckedChangeListener()`.
957 domStorageEnabledSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
959 public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
962 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_enabled));
964 // Set the icon according to the theme.
965 if (MainWebViewActivity.darkTheme) {
966 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_dark));
968 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_light));
974 // Set the `formDataEnabledSwitch` `OnCheckedChangeListener()`.
975 formDataEnabledSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
977 public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
980 formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_enabled));
982 // Set the icon according to the theme.
983 if (MainWebViewActivity.darkTheme) {
984 formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_disabled_dark));
986 formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_disabled_light));
992 // Set the `userAgentSpinner` `onItemClickListener()`.
993 userAgentSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
995 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
996 // Store the new user agent string.
997 String newUserAgentString = resources.getStringArray(R.array.domain_settings_user_agent_entry_values)[position];
999 // Set the new user agent.
1000 switch (newUserAgentString) {
1001 case "System default user agent":
1002 // Show `userAgentTextView`.
1003 userAgentTextView.setVisibility(View.VISIBLE);
1005 // Hide `customUserAgentEditText`.
1006 customUserAgentEditText.setVisibility(View.GONE);
1008 // Set the user text.
1009 switch (defaultUserAgentString) {
1010 case "WebView default user agent":
1011 // Display the `WebView` default user agent.
1012 userAgentTextView.setText(webViewDefaultUserAgentString);
1015 case "Custom user agent":
1016 // Display the custom user agent.
1017 userAgentTextView.setText(defaultCustomUserAgentString);
1021 // Display the text from `defaultUserAgentString`.
1022 userAgentTextView.setText(defaultUserAgentString);
1026 case "WebView default user agent":
1027 // Show `userAgentTextView` and set the text.
1028 userAgentTextView.setVisibility(View.VISIBLE);
1029 userAgentTextView.setText(webViewDefaultUserAgentString);
1031 // Hide `customUserAgentEditText`.
1032 customUserAgentEditText.setVisibility(View.GONE);
1035 case "Custom user agent":
1036 // Hide `userAgentTextView`.
1037 userAgentTextView.setVisibility(View.GONE);
1039 // Show `customUserAgentEditText` and set `userAgentString` as the text.
1040 customUserAgentEditText.setVisibility(View.VISIBLE);
1041 customUserAgentEditText.setText(currentUserAgentString);
1045 // Show `userAgentTextView` and set the text.
1046 userAgentTextView.setVisibility(View.VISIBLE);
1047 userAgentTextView.setText(newUserAgentString);
1049 // Hide `customUserAgentEditText`.
1050 customUserAgentEditText.setVisibility(View.GONE);
1055 public void onNothingSelected(AdapterView<?> parent) {
1060 // Set the `fontSizeSpinner` `onItemSelectedListener()`.
1061 fontSizeSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1063 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1064 // Update the display options for `fontSizeTextView`.
1065 if (position == 0) { // System default font size has been selected. Display `fontSizeTextView`.
1066 fontSizeTextView.setVisibility(View.VISIBLE);
1067 } else { // A custom font size has been selected. Hide `fontSizeTextView`.
1068 fontSizeTextView.setVisibility(View.GONE);
1073 public void onNothingSelected(AdapterView<?> parent) {
1078 // Set the `displayWebpageImagesSpinner` `onItemSelectedListener()`.
1079 displayWebpageImagesSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1081 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1082 // Update the icon and the visibility of `displayImagesTextView`.
1084 case DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_SYSTEM_DEFAULT:
1085 if (defaultDisplayWebpageImagesBoolean) {
1086 // Set the icon according to the theme.
1087 if (MainWebViewActivity.darkTheme) {
1088 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_dark));
1090 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_light));
1093 // Set the icon according to the theme.
1094 if (MainWebViewActivity.darkTheme) {
1095 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_dark));
1097 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_light));
1101 // Show `displayImagesTextView`.
1102 displayImagesTextView.setVisibility(View.VISIBLE);
1105 case DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_ENABLED:
1106 // Set the icon according to the theme.
1107 if (MainWebViewActivity.darkTheme) {
1108 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_dark));
1110 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_light));
1113 // Hide `displayImagesTextView`.
1114 displayImagesTextView.setVisibility(View.GONE);
1117 case DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_DISABLED:
1118 // Set the icon according to the theme.
1119 if (MainWebViewActivity.darkTheme) {
1120 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_dark));
1122 displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_light));
1125 // Hide `displayImagesTextView`.
1126 displayImagesTextView.setVisibility(View.GONE);
1132 public void onNothingSelected(AdapterView<?> parent) {
1137 // Set the `nightModeSpinner` `onItemSelectedListener()`.
1138 nightModeSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
1140 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
1141 // Update the icon and the visibility of `nightModeTextView`. Once minimum API >= 21 we can use a selector as the tint mode instead of specifying different icons.
1143 case DomainsDatabaseHelper.NIGHT_MODE_SYSTEM_DEFAULT:
1144 if (defaultNightModeBoolean) { // Night mode enabled by default.
1145 // Set the icon according to the theme.
1146 if (MainWebViewActivity.darkTheme) {
1147 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_dark));
1149 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_light));
1151 } else { // Night mode disabled by default.
1152 // Set the icon according to the theme.
1153 if (MainWebViewActivity.darkTheme) {
1154 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_dark));
1156 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_light));
1160 // Show `nightModeTextView`.
1161 nightModeTextView.setVisibility(View.VISIBLE);
1164 case DomainsDatabaseHelper.NIGHT_MODE_ENABLED:
1165 // Set the icon according to the theme.
1166 if (MainWebViewActivity.darkTheme) {
1167 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_dark));
1169 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_enabled_light));
1172 // Hide `nightModeTextView`.
1173 nightModeTextView.setVisibility(View.GONE);
1176 case DomainsDatabaseHelper.NIGHT_MODE_DISABLED:
1177 // Set the icon according to the theme.
1178 if (MainWebViewActivity.darkTheme) {
1179 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_dark));
1181 nightModeImageView.setImageDrawable(resources.getDrawable(R.drawable.night_mode_disabled_light));
1184 // Hide `nightModeTextView`.
1185 nightModeTextView.setVisibility(View.GONE);
1189 // Create a `boolean` to store the current night mode setting.
1190 boolean currentNightModeEnabled = (position == DomainsDatabaseHelper.NIGHT_MODE_ENABLED) || ((position == DomainsDatabaseHelper.NIGHT_MODE_SYSTEM_DEFAULT) && defaultNightModeBoolean);
1192 // Disable the JavaScript `Switch` if night mode is enabled.
1193 if (currentNightModeEnabled) {
1194 javaScriptEnabledSwitch.setEnabled(false);
1196 javaScriptEnabledSwitch.setEnabled(true);
1199 // Update the JavaScript icon.
1200 if ((javaScriptEnabledInt == 1) || currentNightModeEnabled) {
1201 javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.javascript_enabled));
1203 javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.privacy_mode));
1206 // Update the DOM storage status.
1207 if ((javaScriptEnabledInt == 1) || currentNightModeEnabled) { // JavaScript is enabled.
1208 // Enable the DOM storage `Switch`.
1209 domStorageEnabledSwitch.setEnabled(true);
1211 // Set the DOM storage status. Once minimum API >= 21 we can use a selector as the tint mode instead of specifying different icons.
1212 if (domStorageEnabledInt == 1) { // Both JavaScript and DOM storage are enabled.
1213 domStorageEnabledSwitch.setChecked(true);
1214 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_enabled));
1215 } else { // JavaScript is enabled but DOM storage is disabled.
1216 // Set the DOM storage switch to off.
1217 domStorageEnabledSwitch.setChecked(false);
1219 // Set the icon according to the theme.
1220 if (MainWebViewActivity.darkTheme) {
1221 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_dark));
1223 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_light));
1226 } else { // JavaScript is disabled.
1227 // Disable the DOM storage `Switch`.
1228 domStorageEnabledSwitch.setEnabled(false);
1230 // Set the checked status of DOM storage.
1231 if (domStorageEnabledInt == 1) { // DOM storage is enabled but JavaScript is disabled.
1232 domStorageEnabledSwitch.setChecked(true);
1233 } else { // Both JavaScript and DOM storage are disabled.
1234 domStorageEnabledSwitch.setChecked(false);
1237 // Set the icon according to the theme.
1238 if (MainWebViewActivity.darkTheme) {
1239 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_dark));
1241 domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_light));
1247 public void onNothingSelected(AdapterView<?> parent) {
1252 // Set the `pinnedSSLCertificateSwitch` `onCheckedChangeListener()`.
1253 pinnedSslCertificateSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
1255 public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
1257 if (isChecked) { // Pinned SSL certificate is enabled.
1258 // Set the icon according to the theme.
1259 if (MainWebViewActivity.darkTheme) {
1260 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_dark));
1262 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_light));
1265 // Update the visibility of the saved SSL certificate.
1266 if (savedSslCertificateIssuedToCNameString == null) {
1267 savedSslCertificateLinearLayout.setVisibility(View.GONE);
1269 savedSslCertificateLinearLayout.setVisibility(View.VISIBLE);
1272 // Update the visibility of the current website SSL certificate.
1273 if (currentWebsiteSslCertificate == null) {
1274 // Hide the SSL certificate.
1275 currentWebsiteCertificateLinearLayout.setVisibility(View.GONE);
1277 // Show the instruction.
1278 noCurrentWebsiteCertificateTextView.setVisibility(View.VISIBLE);
1280 // Show the SSL certificate.
1281 currentWebsiteCertificateLinearLayout.setVisibility(View.VISIBLE);
1283 // Hide the instruction.
1284 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
1287 // Set the status of the radio buttons.
1288 if (savedSslCertificateLinearLayout.getVisibility() == View.VISIBLE) { // The saved SSL certificate is displayed.
1289 savedSslCertificateRadioButton.setChecked(true);
1290 currentWebsiteCertificateRadioButton.setChecked(false);
1291 } else if (currentWebsiteCertificateLinearLayout.getVisibility() == View.VISIBLE) { // The saved SSL certificate is hidden but the current website SSL certificate is visible.
1292 currentWebsiteCertificateRadioButton.setChecked(true);
1293 savedSslCertificateRadioButton.setChecked(false);
1294 } else { // Neither SSL certificate is visible.
1295 savedSslCertificateRadioButton.setChecked(false);
1296 currentWebsiteCertificateRadioButton.setChecked(false);
1298 } else { // Pinned SSL certificate is disabled.
1299 // Set the icon according to the theme.
1300 if (MainWebViewActivity.darkTheme) {
1301 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_dark));
1303 pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_light));
1306 // Hide the SSl certificates and instructions.
1307 savedSslCertificateLinearLayout.setVisibility(View.GONE);
1308 currentWebsiteCertificateLinearLayout.setVisibility(View.GONE);
1309 noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
1311 // Uncheck the radio buttons.
1312 savedSslCertificateRadioButton.setChecked(false);
1313 currentWebsiteCertificateRadioButton.setChecked(false);
1318 savedSslCertificateLinearLayout.setOnClickListener(new View.OnClickListener() {
1320 public void onClick(View v) {
1321 savedSslCertificateRadioButton.setChecked(true);
1322 currentWebsiteCertificateRadioButton.setChecked(false);
1326 savedSslCertificateRadioButton.setOnClickListener(new View.OnClickListener() {
1328 public void onClick(View v) {
1329 savedSslCertificateRadioButton.setChecked(true);
1330 currentWebsiteCertificateRadioButton.setChecked(false);
1334 currentWebsiteCertificateLinearLayout.setOnClickListener(new View.OnClickListener() {
1336 public void onClick(View v) {
1337 currentWebsiteCertificateRadioButton.setChecked(true);
1338 savedSslCertificateRadioButton.setChecked(false);
1342 currentWebsiteCertificateRadioButton.setOnClickListener(new View.OnClickListener() {
1344 public void onClick(View v) {
1345 currentWebsiteCertificateRadioButton.setChecked(true);
1346 savedSslCertificateRadioButton.setChecked(false);
1350 return domainSettingsView;
1353 private boolean checkDomainNameAgainstCertificate(String domainName, String certificateCommonName) {
1354 // Initialize `domainNamesMatch`.
1355 boolean domainNamesMatch = false;
1357 // Check if the domains match.
1358 if (domainName.equals(certificateCommonName)) {
1359 domainNamesMatch = true;
1362 // 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`.
1363 //noinspection ConstantConditions
1364 if ((domainName != null) && (certificateCommonName != null)) {
1365 // If `domainName` starts with a wildcard, check the base domain against all the subdomains of `certificateCommonName`.
1366 if (!domainNamesMatch && domainName.startsWith("*.") && (domainName.length() > 2)) {
1367 // Remove the initial `*.`.
1368 String baseDomainName = domainName.substring(2);
1370 // Setup a copy of `certificateCommonName` to test subdomains.
1371 String certificateCommonNameSubdomain = certificateCommonName;
1373 // Check all the subdomains in `certificateCommonNameSubdomain` against `baseDomainName`.
1374 while (!domainNamesMatch && certificateCommonNameSubdomain.contains(".")) { // Stop checking if we know that `domainNamesMatch` is `true` or if we run out of `.`.
1375 // Test the `certificateCommonNameSubdomain` against `baseDomainName`.
1376 if (certificateCommonNameSubdomain.equals(baseDomainName)) {
1377 domainNamesMatch = true;
1380 // Strip out the lowest subdomain of `certificateCommonNameSubdomain`.
1382 certificateCommonNameSubdomain = certificateCommonNameSubdomain.substring(certificateCommonNameSubdomain.indexOf(".") + 1);
1383 } catch (IndexOutOfBoundsException e) { // `certificateCommonNameSubdomain` ends with `.`.
1384 certificateCommonNameSubdomain = "";
1389 // If `certificateCommonName` starts with a wildcard, check the base common name against all the subdomains of `domainName`.
1390 if (!domainNamesMatch && certificateCommonName.startsWith("*.") && (certificateCommonName.length() > 2)) {
1391 // Remove the initial `*.`.
1392 String baseCertificateCommonName = certificateCommonName.substring(2);
1394 // Setup a copy of `domainName` to test subdomains.
1395 String domainNameSubdomain = domainName;
1397 // Check all the subdomains in `domainNameSubdomain` against `baseCertificateCommonName`.
1398 while (!domainNamesMatch && domainNameSubdomain.contains(".") && (domainNameSubdomain.length() > 2)) {
1399 // Test the `domainNameSubdomain` against `baseCertificateCommonName`.
1400 if (domainNameSubdomain.equals(baseCertificateCommonName)) {
1401 domainNamesMatch = true;
1404 // Strip out the lowest subdomain of `domainNameSubdomain`.
1406 domainNameSubdomain = domainNameSubdomain.substring(domainNameSubdomain.indexOf(".") + 1);
1407 } catch (IndexOutOfBoundsException e) { // `domainNameSubdomain` ends with `.`.
1408 domainNameSubdomain = "";
1413 // If both names start with a wildcard, check if the root of one contains the root of the other.
1414 if (!domainNamesMatch && domainName.startsWith("*.") && (domainName.length() > 2) && certificateCommonName.startsWith("*.") && (certificateCommonName.length() > 2)) {
1415 // Remove the wildcards.
1416 String rootDomainName = domainName.substring(2);
1417 String rootCertificateCommonName = certificateCommonName.substring(2);
1419 // Check if one name ends with the contents of the other. If so, there will be overlap in the their wildcard subdomains.
1420 if (rootDomainName.endsWith(rootCertificateCommonName) || rootCertificateCommonName.endsWith(rootDomainName)) {
1421 domainNamesMatch = true;
1426 return domainNamesMatch;