2 * Copyright © 2017-2020 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.dialogs;
22 import android.annotation.SuppressLint;
23 import android.app.Dialog;
24 import android.content.Context;
25 import android.content.DialogInterface;
26 import android.content.SharedPreferences;
27 import android.content.res.Configuration;
28 import android.graphics.Bitmap;
29 import android.graphics.drawable.BitmapDrawable;
30 import android.graphics.drawable.Drawable;
31 import android.net.Uri;
32 import android.net.http.SslCertificate;
33 import android.os.Bundle;
34 import android.preference.PreferenceManager;
35 import android.text.SpannableStringBuilder;
36 import android.text.Spanned;
37 import android.text.style.ForegroundColorSpan;
38 import android.view.View;
39 import android.view.ViewGroup;
40 import android.view.WindowManager;
41 import android.widget.TextView;
43 import com.google.android.material.tabs.TabLayout;
45 import com.stoutner.privacybrowser.R;
46 import com.stoutner.privacybrowser.activities.MainWebViewActivity;
47 import com.stoutner.privacybrowser.fragments.WebViewTabFragment;
48 import com.stoutner.privacybrowser.views.NestedScrollWebView;
49 import com.stoutner.privacybrowser.views.WrapVerticalContentViewPager;
50 import com.stoutner.privacybrowser.helpers.DomainsDatabaseHelper;
52 import java.text.DateFormat;
53 import java.util.ArrayList;
54 import java.util.Date;
56 import androidx.annotation.NonNull;
57 import androidx.appcompat.app.AlertDialog;
58 import androidx.core.content.ContextCompat;
59 import androidx.fragment.app.DialogFragment; // The AndroidX dialog fragment must be used or an error is produced on API <=22.
60 import androidx.viewpager.widget.PagerAdapter;
62 public class PinnedMismatchDialog extends DialogFragment {
63 // The public interface is used to send information back to the parent activity.
64 public interface PinnedMismatchListener {
65 void pinnedErrorGoBack();
68 // Declare the class variables.
69 private PinnedMismatchListener pinnedMismatchListener;
70 private NestedScrollWebView nestedScrollWebView;
71 private String currentSslIssuedToCName;
72 private String currentSslIssuedToOName;
73 private String currentSslIssuedToUName;
74 private String currentSslIssuedByCName;
75 private String currentSslIssuedByOName;
76 private String currentSslIssuedByUName;
77 private Date currentSslStartDate;
78 private Date currentSslEndDate;
81 public void onAttach(@NonNull Context context) {
82 // Run the default commands.
83 super.onAttach(context);
85 // Get a handle for the listener from the launching context.
86 pinnedMismatchListener = (PinnedMismatchListener) context;
89 public static PinnedMismatchDialog displayDialog(long webViewFragmentId) {
90 // Create an arguments bundle.
91 Bundle argumentsBundle = new Bundle();
93 // Store the WebView fragment ID in the bundle.
94 argumentsBundle.putLong("webview_fragment_id", webViewFragmentId);
96 // Create a new instance of the pinned mismatch dialog.
97 PinnedMismatchDialog pinnedMismatchDialog = new PinnedMismatchDialog();
99 // Add the arguments bundle to the new instance.
100 pinnedMismatchDialog.setArguments(argumentsBundle);
103 return pinnedMismatchDialog;
106 // `@SuppressLint("InflateParams")` removes the warning about using `null` as the parent view group when inflating the `AlertDialog`.
107 @SuppressLint("InflateParams")
110 public Dialog onCreateDialog(Bundle savedInstanceState) {
111 // Get the arguments.
112 Bundle arguments = getArguments();
114 // Remove the incorrect lint warning below that `.getArguments().getInt()` might be null.
115 assert arguments != null;
117 // Get the current position of this WebView fragment.
118 int webViewPosition = MainWebViewActivity.webViewPagerAdapter.getPositionForId(arguments.getLong("webview_fragment_id"));
120 // Get the WebView tab fragment.
121 WebViewTabFragment webViewTabFragment = MainWebViewActivity.webViewPagerAdapter.getPageFragment(webViewPosition);
123 // Get the fragment view.
124 View fragmentView = webViewTabFragment.getView();
126 // Remove the incorrect lint warning below that the fragment view might be null.
127 assert fragmentView != null;
129 // Get a handle for the current WebView.
130 nestedScrollWebView = fragmentView.findViewById(R.id.nestedscroll_webview);
132 // Use an alert dialog builder to create the alert dialog.
133 AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(requireContext(), R.style.PrivacyBrowserAlertDialog);
136 Context context = getContext();
138 // Remove the incorrect lint warning below that the context might be null.
139 assert context != null;
141 // Get the favorite icon.
142 Bitmap favoriteIconBitmap = nestedScrollWebView.getFavoriteOrDefaultIcon();
144 // Get the default favorite icon drawable. `ContextCompat` must be used until API >= 21.
145 Drawable defaultFavoriteIconDrawable = ContextCompat.getDrawable(context, R.drawable.world);
147 // Cast the favorite icon drawable to a bitmap drawable.
148 BitmapDrawable defaultFavoriteIconBitmapDrawable = (BitmapDrawable) defaultFavoriteIconDrawable;
150 // Remove the incorrect warning below that the favorite icon bitmap drawable might be null.
151 assert defaultFavoriteIconBitmapDrawable != null;
153 // Store the default icon bitmap.
154 Bitmap defaultFavoriteIconBitmap = defaultFavoriteIconBitmapDrawable.getBitmap();
156 // Set the favorite icon as the dialog icon if it exists.
157 if (favoriteIconBitmap.sameAs(defaultFavoriteIconBitmap)) { // There is no website favorite icon.
158 // Get the current theme status.
159 int currentThemeStatus = getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
161 // Set the icon according to the theme.
162 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
163 dialogBuilder.setIcon(R.drawable.ssl_certificate_enabled_night);
165 dialogBuilder.setIcon(R.drawable.ssl_certificate_enabled_day);
167 } else { // There is a favorite icon.
168 // Create a drawable version of the favorite icon.
169 Drawable favoriteIconDrawable = new BitmapDrawable(getResources(), favoriteIconBitmap);
172 dialogBuilder.setIcon(favoriteIconDrawable);
175 // Setup the neutral button.
176 dialogBuilder.setNeutralButton(R.string.update, (DialogInterface dialog, int which) -> {
177 // Initialize the long date variables. If the date is null, a long value of `0` will be stored in the Domains database entry.
178 long currentSslStartDateLong = 0;
179 long currentSslEndDateLong = 0;
181 // Convert the `Dates` into `longs`.
182 if (currentSslStartDate != null) {
183 currentSslStartDateLong = currentSslStartDate.getTime();
186 if (currentSslEndDate != null) {
187 currentSslEndDateLong = currentSslEndDate.getTime();
190 // Initialize the database handler. The `0` specifies the database version, but that is ignored and set instead using a constant in `DomainsDatabaseHelper`.
191 DomainsDatabaseHelper domainsDatabaseHelper = new DomainsDatabaseHelper(context, null, null, 0);
193 // Update the SSL certificate if it is pinned.
194 if (nestedScrollWebView.hasPinnedSslCertificate()) {
195 // Update the pinned SSL certificate in the domain database.
196 domainsDatabaseHelper.updatePinnedSslCertificate(nestedScrollWebView.getDomainSettingsDatabaseId(), currentSslIssuedToCName, currentSslIssuedToOName, currentSslIssuedToUName,
197 currentSslIssuedByCName, currentSslIssuedByOName, currentSslIssuedByUName, currentSslStartDateLong, currentSslEndDateLong);
199 // Update the pinned SSL certificate in the nested scroll WebView.
200 nestedScrollWebView.setPinnedSslCertificate(currentSslIssuedToCName, currentSslIssuedToOName, currentSslIssuedToUName, currentSslIssuedByCName, currentSslIssuedByOName, currentSslIssuedByUName,
201 currentSslStartDate, currentSslEndDate);
204 // Update the IP addresses if they are pinned.
205 if (nestedScrollWebView.hasPinnedIpAddresses()) {
206 // Update the pinned IP addresses in the domain database.
207 domainsDatabaseHelper.updatePinnedIpAddresses(nestedScrollWebView.getDomainSettingsDatabaseId(), nestedScrollWebView.getCurrentIpAddresses());
209 // Update the pinned IP addresses in the nested scroll WebView.
210 nestedScrollWebView.setPinnedIpAddresses(nestedScrollWebView.getCurrentIpAddresses());
214 // Setup the back button.
215 dialogBuilder.setNegativeButton(R.string.back, (DialogInterface dialog, int which) -> {
216 if (nestedScrollWebView.canGoBack()) { // There is a back page in the history.
217 // Invoke the navigate history listener in the calling activity. These commands cannot be run here because they need access to `applyDomainSettings()`.
218 pinnedMismatchListener.pinnedErrorGoBack();
219 } else { // There are no pages to go back to.
221 nestedScrollWebView.loadUrl("");
225 // Setup the proceed button.
226 dialogBuilder.setPositiveButton(R.string.proceed, (DialogInterface dialog, int which) -> {
227 // Do not check the pinned information for this domain again until the domain changes.
228 nestedScrollWebView.setIgnorePinnedDomainInformation(true);
232 dialogBuilder.setTitle(R.string.pinned_mismatch);
234 // Remove the incorrect lint warning below that `getLayoutInflater()` might be null.
235 assert getActivity() != null;
237 // Set the layout. The parent view is `null` because it will be assigned by `AlertDialog`.
238 // For some reason, `getLayoutInflater()` without `getActivity()` produces an endless loop (probably a bug that will be fixed at some point in the future).
239 dialogBuilder.setView(getActivity().getLayoutInflater().inflate(R.layout.pinned_mismatch_linearlayout, null));
241 // Create an alert dialog from the alert dialog builder.
242 final AlertDialog alertDialog = dialogBuilder.create();
244 // Get a handle for the shared preferences.
245 SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getContext());
247 // Get the screenshot preference.
248 boolean allowScreenshots = sharedPreferences.getBoolean("allow_screenshots", false);
250 // Disable screenshots if not allowed.
251 if (!allowScreenshots) {
252 // Remove the warning below that `getWindow()` might be null.
253 assert alertDialog.getWindow() != null;
255 // Disable screenshots.
256 alertDialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE);
259 // Show the alert dialog so the items in the layout can be modified.
262 // Get a handle for the views.
263 WrapVerticalContentViewPager wrapVerticalContentViewPager = alertDialog.findViewById(R.id.pinned_ssl_certificate_mismatch_viewpager);
264 TabLayout tabLayout = alertDialog.findViewById(R.id.pinned_ssl_certificate_mismatch_tablayout);
266 // Remove the incorrect lint warning below that the views might be null.
267 assert wrapVerticalContentViewPager != null;
268 assert tabLayout != null;
270 // Set the view pager adapter.
271 wrapVerticalContentViewPager.setAdapter(new pagerAdapter());
273 // Connect the tab layout to the view pager.
274 tabLayout.setupWithViewPager(wrapVerticalContentViewPager);
276 // Return the alert dialog.
280 private class pagerAdapter extends PagerAdapter {
282 public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
283 // Check to see if the `View` and the `Object` are the same.
284 return (view == object);
288 public int getCount() {
289 // There are two tabs.
294 public CharSequence getPageTitle(int position) {
295 // Return the current tab title.
296 if (position == 0) { // The current SSL certificate tab.
297 return getString(R.string.current);
298 } else { // The pinned SSL certificate tab.
299 return getString(R.string.pinned);
305 public Object instantiateItem(@NonNull ViewGroup container, int position) {
306 // Inflate the scroll view for this tab.
307 ViewGroup tabViewGroup = (ViewGroup) getLayoutInflater().inflate(R.layout.pinned_mismatch_scrollview, container, false);
309 // Get handles for the `TextViews`.
310 TextView domainNameTextView = tabViewGroup.findViewById(R.id.domain_name);
311 TextView ipAddressesTextView = tabViewGroup.findViewById(R.id.ip_addresses);
312 TextView issuedToCNameTextView = tabViewGroup.findViewById(R.id.issued_to_cname);
313 TextView issuedToONameTextView = tabViewGroup.findViewById(R.id.issued_to_oname);
314 TextView issuedToUNameTextView = tabViewGroup.findViewById(R.id.issued_to_uname);
315 TextView issuedByCNameTextView = tabViewGroup.findViewById(R.id.issued_by_cname);
316 TextView issuedByONameTextView = tabViewGroup.findViewById(R.id.issued_by_oname);
317 TextView issuedByUNameTextView = tabViewGroup.findViewById(R.id.issued_by_uname);
318 TextView startDateTextView = tabViewGroup.findViewById(R.id.start_date);
319 TextView endDateTextView = tabViewGroup.findViewById(R.id.end_date);
322 String domainNameLabel = getString(R.string.domain_label) + " ";
323 String ipAddressesLabel = getString(R.string.ip_addresses) + " ";
324 String cNameLabel = getString(R.string.common_name) + " ";
325 String oNameLabel = getString(R.string.organization) + " ";
326 String uNameLabel = getString(R.string.organizational_unit) + " ";
327 String startDateLabel = getString(R.string.start_date) + " ";
328 String endDateLabel = getString(R.string.end_date) + " ";
330 // Convert the URL to a URI.
331 Uri currentUri = Uri.parse(nestedScrollWebView.getUrl());
333 // Get the current host from the URI.
334 String domainName = currentUri.getHost();
336 // Get the current website SSL certificate.
337 SslCertificate sslCertificate = nestedScrollWebView.getCertificate();
339 // Extract the individual pieces of information from the current website SSL certificate if it is not null.
340 if (sslCertificate != null) {
341 currentSslIssuedToCName = sslCertificate.getIssuedTo().getCName();
342 currentSslIssuedToOName = sslCertificate.getIssuedTo().getOName();
343 currentSslIssuedToUName = sslCertificate.getIssuedTo().getUName();
344 currentSslIssuedByCName = sslCertificate.getIssuedBy().getCName();
345 currentSslIssuedByOName = sslCertificate.getIssuedBy().getOName();
346 currentSslIssuedByUName = sslCertificate.getIssuedBy().getUName();
347 currentSslStartDate = sslCertificate.getValidNotBeforeDate();
348 currentSslEndDate = sslCertificate.getValidNotAfterDate();
350 // Initialize the current website SSL certificate variables with blank information.
351 currentSslIssuedToCName = "";
352 currentSslIssuedToOName = "";
353 currentSslIssuedToUName = "";
354 currentSslIssuedByCName = "";
355 currentSslIssuedByOName = "";
356 currentSslIssuedByUName = "";
359 // Get the pinned SSL certificate.
360 ArrayList<Object> pinnedSslCertificateArrayList = nestedScrollWebView.getPinnedSslCertificate();
362 // Extract the arrays from the array list.
363 String[] pinnedSslCertificateStringArray = (String[]) pinnedSslCertificateArrayList.get(0);
364 Date[] pinnedSslCertificateDateArray = (Date[]) pinnedSslCertificateArrayList.get(1);
366 // Setup the domain name spannable string builder.
367 SpannableStringBuilder domainNameStringBuilder = new SpannableStringBuilder(domainNameLabel + domainName);
369 // Initialize the spannable string builders.
370 SpannableStringBuilder ipAddressesStringBuilder;
371 SpannableStringBuilder issuedToCNameStringBuilder;
372 SpannableStringBuilder issuedToONameStringBuilder;
373 SpannableStringBuilder issuedToUNameStringBuilder;
374 SpannableStringBuilder issuedByCNameStringBuilder;
375 SpannableStringBuilder issuedByONameStringBuilder;
376 SpannableStringBuilder issuedByUNameStringBuilder;
377 SpannableStringBuilder startDateStringBuilder;
378 SpannableStringBuilder endDateStringBuilder;
380 // Setup the spannable string builders for each tab.
381 if (position == 0) { // Setup the current settings tab.
382 // Create the string builders.
383 ipAddressesStringBuilder = new SpannableStringBuilder(ipAddressesLabel + nestedScrollWebView.getCurrentIpAddresses());
384 issuedToCNameStringBuilder = new SpannableStringBuilder(cNameLabel + currentSslIssuedToCName);
385 issuedToONameStringBuilder = new SpannableStringBuilder(oNameLabel + currentSslIssuedToOName);
386 issuedToUNameStringBuilder = new SpannableStringBuilder(uNameLabel + currentSslIssuedToUName);
387 issuedByCNameStringBuilder = new SpannableStringBuilder(cNameLabel + currentSslIssuedByCName);
388 issuedByONameStringBuilder = new SpannableStringBuilder(oNameLabel + currentSslIssuedByOName);
389 issuedByUNameStringBuilder = new SpannableStringBuilder(uNameLabel + currentSslIssuedByUName);
391 // Set the dates if they aren't `null`.
392 if (currentSslStartDate == null) {
393 startDateStringBuilder = new SpannableStringBuilder(startDateLabel);
395 startDateStringBuilder = new SpannableStringBuilder(startDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(currentSslStartDate));
398 if (currentSslEndDate == null) {
399 endDateStringBuilder = new SpannableStringBuilder(endDateLabel);
401 endDateStringBuilder = new SpannableStringBuilder(endDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(currentSslEndDate));
403 } else { // Setup the pinned settings tab.
404 // Create the string builders.
405 ipAddressesStringBuilder = new SpannableStringBuilder(ipAddressesLabel + nestedScrollWebView.getPinnedIpAddresses());
406 issuedToCNameStringBuilder = new SpannableStringBuilder(cNameLabel + pinnedSslCertificateStringArray[0]);
407 issuedToONameStringBuilder = new SpannableStringBuilder(oNameLabel + pinnedSslCertificateStringArray[1]);
408 issuedToUNameStringBuilder = new SpannableStringBuilder(uNameLabel + pinnedSslCertificateStringArray[2]);
409 issuedByCNameStringBuilder = new SpannableStringBuilder(cNameLabel + pinnedSslCertificateStringArray[3]);
410 issuedByONameStringBuilder = new SpannableStringBuilder(oNameLabel + pinnedSslCertificateStringArray[4]);
411 issuedByUNameStringBuilder = new SpannableStringBuilder(uNameLabel + pinnedSslCertificateStringArray[5]);
413 // Set the dates if they aren't `null`.
414 if (pinnedSslCertificateDateArray[0] == null) {
415 startDateStringBuilder = new SpannableStringBuilder(startDateLabel);
417 startDateStringBuilder = new SpannableStringBuilder(startDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(pinnedSslCertificateDateArray[0]));
420 if (pinnedSslCertificateDateArray[1] == null) {
421 endDateStringBuilder = new SpannableStringBuilder(endDateLabel);
423 endDateStringBuilder = new SpannableStringBuilder(endDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(pinnedSslCertificateDateArray[1]));
427 // Define the color spans.
428 ForegroundColorSpan blueColorSpan;
429 ForegroundColorSpan redColorSpan;
431 // Get the current theme status.
432 int currentThemeStatus = getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
434 // Set the color spans according to the theme. The deprecated `getResources()` must be used until the minimum API >= 23.
435 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
436 blueColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.violet_500));
437 redColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.red_900));
439 blueColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.blue_700));
440 redColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.red_a700));
443 // Set the domain name to be blue.
444 domainNameStringBuilder.setSpan(blueColorSpan, domainNameLabel.length(), domainNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
446 // Color coordinate the IP addresses if they are pinned.
447 if (nestedScrollWebView.hasPinnedIpAddresses()) {
448 if (nestedScrollWebView.getCurrentIpAddresses().equals(nestedScrollWebView.getPinnedIpAddresses())) {
449 ipAddressesStringBuilder.setSpan(blueColorSpan, ipAddressesLabel.length(), ipAddressesStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
451 ipAddressesStringBuilder.setSpan(redColorSpan, ipAddressesLabel.length(), ipAddressesStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
455 // Color coordinate the SSL certificate fields if they are pinned.
456 if (nestedScrollWebView.hasPinnedSslCertificate()) {
457 if (currentSslIssuedToCName.equals(pinnedSslCertificateStringArray[0])) {
458 issuedToCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), issuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
460 issuedToCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), issuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
463 if (currentSslIssuedToOName.equals(pinnedSslCertificateStringArray[1])) {
464 issuedToONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), issuedToONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
466 issuedToONameStringBuilder.setSpan(redColorSpan, oNameLabel.length(), issuedToONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
469 if (currentSslIssuedToUName.equals(pinnedSslCertificateStringArray[2])) {
470 issuedToUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), issuedToUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
472 issuedToUNameStringBuilder.setSpan(redColorSpan, uNameLabel.length(), issuedToUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
475 if (currentSslIssuedByCName.equals(pinnedSslCertificateStringArray[3])) {
476 issuedByCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), issuedByCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
478 issuedByCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), issuedByCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
481 if (currentSslIssuedByOName.equals(pinnedSslCertificateStringArray[4])) {
482 issuedByONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), issuedByONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
484 issuedByONameStringBuilder.setSpan(redColorSpan, oNameLabel.length(), issuedByONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
487 if (currentSslIssuedByUName.equals(pinnedSslCertificateStringArray[5])) {
488 issuedByUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), issuedByUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
490 issuedByUNameStringBuilder.setSpan(redColorSpan, uNameLabel.length(), issuedByUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
493 if ((currentSslStartDate != null) && currentSslStartDate.equals(pinnedSslCertificateDateArray[0])) {
494 startDateStringBuilder.setSpan(blueColorSpan, startDateLabel.length(), startDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
496 startDateStringBuilder.setSpan(redColorSpan, startDateLabel.length(), startDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
499 if ((currentSslEndDate != null) && currentSslEndDate.equals(pinnedSslCertificateDateArray[1])) {
500 endDateStringBuilder.setSpan(blueColorSpan, endDateLabel.length(), endDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
502 endDateStringBuilder.setSpan(redColorSpan, endDateLabel.length(), endDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
506 // Display the strings.
507 domainNameTextView.setText(domainNameStringBuilder);
508 ipAddressesTextView.setText(ipAddressesStringBuilder);
509 issuedToCNameTextView.setText(issuedToCNameStringBuilder);
510 issuedToONameTextView.setText(issuedToONameStringBuilder);
511 issuedToUNameTextView.setText(issuedToUNameStringBuilder);
512 issuedByCNameTextView.setText(issuedByCNameStringBuilder);
513 issuedByONameTextView.setText(issuedByONameStringBuilder);
514 issuedByUNameTextView.setText(issuedByUNameStringBuilder);
515 startDateTextView.setText(startDateStringBuilder);
516 endDateTextView.setText(endDateStringBuilder);
519 container.addView(tabViewGroup);