]> gitweb.stoutner.com Git - PrivacyBrowserAndroid.git/blob - app/src/main/java/com/stoutner/privacybrowser/dialogs/PinnedMismatchDialog.java
0a25771dfbb994c4605559a31ccc61a004bbf3e9
[PrivacyBrowserAndroid.git] / app / src / main / java / com / stoutner / privacybrowser / dialogs / PinnedMismatchDialog.java
1 /*
2  * Copyright © 2017-2019 Soren Stoutner <soren@stoutner.com>.
3  *
4  * This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
5  *
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.
10  *
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.
15  *
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/>.
18  */
19
20 package com.stoutner.privacybrowser.dialogs;
21
22 import android.annotation.SuppressLint;
23 import android.app.AlertDialog;
24 import android.app.Dialog;
25 import android.content.Context;
26 import android.content.DialogInterface;
27 import android.graphics.drawable.BitmapDrawable;
28 import android.graphics.drawable.Drawable;
29 import android.net.Uri;
30 import android.net.http.SslCertificate;
31 import android.os.Bundle;
32 import android.support.annotation.NonNull;
33 import android.support.design.widget.TabLayout;
34 import android.support.v4.view.PagerAdapter;
35 // `AppCompatDialogFragment` is used instead of `DialogFragment` to avoid an error on API <=22.
36 import android.support.v7.app.AppCompatDialogFragment;
37 import android.text.SpannableStringBuilder;
38 import android.text.Spanned;
39 import android.text.style.ForegroundColorSpan;
40 import android.view.LayoutInflater;
41 import android.view.View;
42 import android.view.ViewGroup;
43 import android.view.WindowManager;
44 import android.widget.TextView;
45
46 import com.stoutner.privacybrowser.R;
47 import com.stoutner.privacybrowser.activities.MainWebViewActivity;
48 import com.stoutner.privacybrowser.definitions.WrapVerticalContentViewPager;
49 import com.stoutner.privacybrowser.helpers.DomainsDatabaseHelper;
50
51 import java.text.DateFormat;
52 import java.util.Date;
53
54 public class PinnedMismatchDialog extends AppCompatDialogFragment {
55     // Instantiate the class variables.
56     private PinnedMismatchListener pinnedMismatchListener;
57     private LayoutInflater layoutInflater;
58     private String currentSslIssuedToCName;
59     private String currentSslIssuedToOName;
60     private String currentSslIssuedToUName;
61     private String currentSslIssuedByCName;
62     private String currentSslIssuedByOName;
63     private String currentSslIssuedByUName;
64     private Date currentSslStartDate;
65     private Date currentSslEndDate;
66     private boolean pinnedSslCertificate;
67     private boolean pinnedIpAddresses;
68
69     // The public interface is used to send information back to the parent activity.
70     public interface PinnedMismatchListener {
71         void onPinnedMismatchBack();
72
73         void onPinnedMismatchProceed();
74     }
75
76     // Check to make sure that the parent activity implements the listener.
77     public void onAttach(Context context) {
78         // Run the default commands.
79         super.onAttach(context);
80
81         // Get a handle for `PinnedSslCertificateMismatchListener` from the launching context.
82         pinnedMismatchListener = (PinnedMismatchListener) context;
83     }
84
85     public static PinnedMismatchDialog displayDialog(boolean pinnedSslCertificate, boolean pinnedIpAddresses) {
86         // Create an arguments bundle.
87         Bundle argumentsBundle = new Bundle();
88
89         // Store the variables in the bundle.
90         argumentsBundle.putBoolean("Pinned_SSL_Certificate", pinnedSslCertificate);
91         argumentsBundle.putBoolean("Pinned_IP_Addresses", pinnedIpAddresses);
92
93         // Add the arguments bundle to this instance of `PinnedMismatchDialog`.
94         PinnedMismatchDialog thisPinnedMismatchDialog = new PinnedMismatchDialog();
95         thisPinnedMismatchDialog.setArguments(argumentsBundle);
96         return thisPinnedMismatchDialog;
97     }
98
99     // `@SuppressLing("InflateParams")` removes the warning about using `null` as the parent view group when inflating the `AlertDialog`.
100     @SuppressLint("InflateParams")
101     @Override
102     @NonNull
103     public Dialog onCreateDialog(Bundle savedInstanceState) {
104         // Remove the incorrect lint warning that `getActivity()` might be null.
105         assert getActivity() != null;
106
107         // Get the activity's layout inflater.
108         layoutInflater = getActivity().getLayoutInflater();
109
110         // Use an alert dialog builder to create the alert dialog.
111         AlertDialog.Builder dialogBuilder;
112
113         // Set the style according to the theme.
114         if (MainWebViewActivity.darkTheme) {
115             // Set the dialog theme.
116             dialogBuilder = new AlertDialog.Builder(getActivity(), R.style.PrivacyBrowserAlertDialogDark);
117         } else {
118             // Set the dialog theme.
119             dialogBuilder = new AlertDialog.Builder(getActivity(), R.style.PrivacyBrowserAlertDialogLight);
120         }
121
122         // Remove the incorrect lint warning below that `.getArguments.getBoolean()` might be null.
123         assert getArguments() != null;
124
125         // Get the variables from the bundle.
126         pinnedSslCertificate = getArguments().getBoolean("Pinned_SSL_Certificate");
127         pinnedIpAddresses = getArguments().getBoolean("Pinned_IP_Addresses");
128
129         // Set the favorite icon as the dialog icon if it exists.
130         if (MainWebViewActivity.favoriteIconBitmap.equals(MainWebViewActivity.favoriteIconDefaultBitmap)) {  // There is no favorite icon.
131             // Set the icon according to the theme.
132             if (MainWebViewActivity.darkTheme) {
133                 dialogBuilder.setIcon(R.drawable.ssl_certificate_enabled_dark);
134             } else {
135                 dialogBuilder.setIcon(R.drawable.ssl_certificate_enabled_light);
136             }
137         } else {  // There is a favorite icon.
138             // Create a drawable version of the favorite icon.
139             Drawable favoriteIconDrawable = new BitmapDrawable(getResources(), MainWebViewActivity.favoriteIconBitmap);
140
141             // Set the icon.
142             dialogBuilder.setIcon(favoriteIconDrawable);
143         }
144
145         // Setup the neutral button.
146         dialogBuilder.setNeutralButton(R.string.update, (DialogInterface dialog, int which) -> {
147             // Initialize the long date variables.  If the date is null, a long value of `0` will be stored in the Domains database entry.
148             long currentSslStartDateLong = 0;
149             long currentSslEndDateLong = 0;
150
151             // Convert the `Dates` into `longs`.
152             if (currentSslStartDate != null) {
153                 currentSslStartDateLong = currentSslStartDate.getTime();
154             }
155
156             if (currentSslEndDate != null) {
157                 currentSslEndDateLong = currentSslEndDate.getTime();
158             }
159
160             // Initialize the database handler.  The `0` specifies the database version, but that is ignored and set instead using a constant in `DomainsDatabaseHelper`.
161             DomainsDatabaseHelper domainsDatabaseHelper = new DomainsDatabaseHelper(getContext(), null, null, 0);
162
163             // Update the SSL certificate if it is pinned.
164             if (pinnedSslCertificate) {
165                 // Update the pinned SSL certificate in the domain database.
166                 domainsDatabaseHelper.updatePinnedSslCertificate(MainWebViewActivity.domainSettingsDatabaseId, currentSslIssuedToCName, currentSslIssuedToOName, currentSslIssuedToUName,
167                         currentSslIssuedByCName, currentSslIssuedByOName, currentSslIssuedByUName, currentSslStartDateLong, currentSslEndDateLong);
168
169                 // Update the pinned SSL certificate class variables to match the information that is now in the database.
170                 MainWebViewActivity.pinnedSslIssuedToCName = currentSslIssuedToCName;
171                 MainWebViewActivity.pinnedSslIssuedToOName = currentSslIssuedToOName;
172                 MainWebViewActivity.pinnedSslIssuedToUName = currentSslIssuedToUName;
173                 MainWebViewActivity.pinnedSslIssuedByCName = currentSslIssuedByCName;
174                 MainWebViewActivity.pinnedSslIssuedByOName = currentSslIssuedByOName;
175                 MainWebViewActivity.pinnedSslIssuedByUName = currentSslIssuedByUName;
176                 MainWebViewActivity.pinnedSslStartDate = currentSslStartDate;
177                 MainWebViewActivity.pinnedSslEndDate = currentSslEndDate;
178             }
179
180             // Update the IP addresses if they are pinned.
181             if (pinnedIpAddresses) {
182                 // Update the pinned IP addresses in the domain database.
183                 domainsDatabaseHelper.updatePinnedIpAddresses(MainWebViewActivity.domainSettingsDatabaseId, MainWebViewActivity.currentHostIpAddresses);
184
185                 // Update the pinned IP addresses class variable to match the information that is now in the database.
186                 MainWebViewActivity.pinnedHostIpAddresses = MainWebViewActivity.currentHostIpAddresses;
187             }
188         });
189
190         // Setup the negative button.
191         dialogBuilder.setNegativeButton(R.string.back, (DialogInterface dialog, int which) -> {
192             // Call the `onSslMismatchBack` public interface to send the `WebView` back one page.
193             pinnedMismatchListener.onPinnedMismatchBack();
194         });
195
196         // Setup the positive button.
197         dialogBuilder.setPositiveButton(R.string.proceed, (DialogInterface dialog, int which) -> {
198             // Call the `onSslMismatchProceed` public interface.
199             pinnedMismatchListener.onPinnedMismatchProceed();
200         });
201
202         // Set the title.
203         dialogBuilder.setTitle(R.string.pinned_mismatch);
204
205         // Set the layout.  The parent view is `null` because it will be assigned by `AlertDialog`.
206         dialogBuilder.setView(layoutInflater.inflate(R.layout.pinned_mismatch_linearlayout, null));
207
208         // Create an alert dialog from the alert dialog builder.
209         final AlertDialog alertDialog = dialogBuilder.create();
210
211         // Disable screenshots if not allowed.
212         if (!MainWebViewActivity.allowScreenshots) {
213             // Remove the warning below that `getWindow()` might be null.
214             assert alertDialog.getWindow() != null;
215
216             // Disable screenshots.
217             alertDialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE);
218         }
219
220         // Show the alert dialog so the items in the layout can be modified.
221         alertDialog.show();
222
223         //  Setup the view pager.
224         WrapVerticalContentViewPager wrapVerticalContentViewPager = alertDialog.findViewById(R.id.pinned_ssl_certificate_mismatch_viewpager);
225         wrapVerticalContentViewPager.setAdapter(new pagerAdapter());
226
227         // Setup the tab layout and connect it to the view pager.
228         TabLayout tabLayout = alertDialog.findViewById(R.id.pinned_ssl_certificate_mismatch_tablayout);
229         tabLayout.setupWithViewPager(wrapVerticalContentViewPager);
230
231         // `onCreateDialog()` requires the return of an `AlertDialog`.
232         return alertDialog;
233     }
234
235     private class pagerAdapter extends PagerAdapter {
236         @Override
237         public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
238             // Check to see if the `View` and the `Object` are the same.
239             return (view == object);
240         }
241
242         @Override
243         public int getCount() {
244             // There are two tabs.
245             return 2;
246         }
247
248         @Override
249         public CharSequence getPageTitle(int position) {
250             // Return the current tab title.
251             if (position == 0) {  // The current SSL certificate tab.
252                 return getString(R.string.current);
253             } else {  // The pinned SSL certificate tab.
254                 return getString(R.string.pinned);
255             }
256         }
257
258         @Override
259         @NonNull
260         public Object instantiateItem(@NonNull ViewGroup container, int position) {
261             // Inflate the scroll view for this tab.
262             ViewGroup tabViewGroup = (ViewGroup) layoutInflater.inflate(R.layout.pinned_mismatch_scrollview, container, false);
263
264             // Get handles for the `TextViews`.
265             TextView domainNameTextView = tabViewGroup.findViewById(R.id.domain_name);
266             TextView ipAddressesTextView = tabViewGroup.findViewById(R.id.ip_addresses);
267             TextView issuedToCNameTextView = tabViewGroup.findViewById(R.id.issued_to_cname);
268             TextView issuedToONameTextView = tabViewGroup.findViewById(R.id.issued_to_oname);
269             TextView issuedToUNameTextView = tabViewGroup.findViewById(R.id.issued_to_uname);
270             TextView issuedByCNameTextView = tabViewGroup.findViewById(R.id.issued_by_cname);
271             TextView issuedByONameTextView = tabViewGroup.findViewById(R.id.issued_by_oname);
272             TextView issuedByUNameTextView = tabViewGroup.findViewById(R.id.issued_by_uname);
273             TextView startDateTextView = tabViewGroup.findViewById(R.id.start_date);
274             TextView endDateTextView = tabViewGroup.findViewById(R.id.end_date);
275
276             // Setup the labels.
277             String domainNameLabel = getString(R.string.domain_label) + "  ";
278             String ipAddressesLabel = getString(R.string.ip_addresses) + "  ";
279             String cNameLabel = getString(R.string.common_name) + "  ";
280             String oNameLabel = getString(R.string.organization) + "  ";
281             String uNameLabel = getString(R.string.organizational_unit) + "  ";
282             String startDateLabel = getString(R.string.start_date) + "  ";
283             String endDateLabel = getString(R.string.end_date) + "  ";
284
285             // Get a URI for the URL.
286             Uri currentUri = Uri.parse(MainWebViewActivity.formattedUrlString);
287
288             // Get the current host from the URI.
289             String domainName = currentUri.getHost();
290
291             // Get the current website SSL certificate.
292             SslCertificate sslCertificate = MainWebViewActivity.sslCertificate;
293
294             // Extract the individual pieces of information from the current website SSL certificate if it is not null.
295             if (sslCertificate != null) {
296                 currentSslIssuedToCName = sslCertificate.getIssuedTo().getCName();
297                 currentSslIssuedToOName = sslCertificate.getIssuedTo().getOName();
298                 currentSslIssuedToUName = sslCertificate.getIssuedTo().getUName();
299                 currentSslIssuedByCName = sslCertificate.getIssuedBy().getCName();
300                 currentSslIssuedByOName = sslCertificate.getIssuedBy().getOName();
301                 currentSslIssuedByUName = sslCertificate.getIssuedBy().getUName();
302                 currentSslStartDate = sslCertificate.getValidNotBeforeDate();
303                 currentSslEndDate = sslCertificate.getValidNotAfterDate();
304             } else {
305                 // Initialize the current website SSL certificate variables with blank information.
306                 currentSslIssuedToCName = "";
307                 currentSslIssuedToOName = "";
308                 currentSslIssuedToUName = "";
309                 currentSslIssuedByCName = "";
310                 currentSslIssuedByOName = "";
311                 currentSslIssuedByUName = "";
312             }
313
314             // Setup the domain name spannable string builder.
315             SpannableStringBuilder domainNameStringBuilder = new SpannableStringBuilder(domainNameLabel + domainName);
316
317             // Initialize the spannable string builders.
318             SpannableStringBuilder ipAddressesStringBuilder;
319             SpannableStringBuilder issuedToCNameStringBuilder;
320             SpannableStringBuilder issuedToONameStringBuilder;
321             SpannableStringBuilder issuedToUNameStringBuilder;
322             SpannableStringBuilder issuedByCNameStringBuilder;
323             SpannableStringBuilder issuedByONameStringBuilder;
324             SpannableStringBuilder issuedByUNameStringBuilder;
325             SpannableStringBuilder startDateStringBuilder;
326             SpannableStringBuilder endDateStringBuilder;
327
328             // Setup the spannable string builders for each tab.
329             if (position == 0) {  // Setup the current settings tab.
330                 // Create the string builders.
331                 ipAddressesStringBuilder = new SpannableStringBuilder(ipAddressesLabel + MainWebViewActivity.currentHostIpAddresses);
332                 issuedToCNameStringBuilder = new SpannableStringBuilder(cNameLabel + currentSslIssuedToCName);
333                 issuedToONameStringBuilder = new SpannableStringBuilder(oNameLabel + currentSslIssuedToOName);
334                 issuedToUNameStringBuilder = new SpannableStringBuilder(uNameLabel + currentSslIssuedToUName);
335                 issuedByCNameStringBuilder = new SpannableStringBuilder(cNameLabel + currentSslIssuedByCName);
336                 issuedByONameStringBuilder = new SpannableStringBuilder(oNameLabel + currentSslIssuedByOName);
337                 issuedByUNameStringBuilder = new SpannableStringBuilder(uNameLabel + currentSslIssuedByUName);
338
339                 // Set the dates if they aren't `null`.
340                 if (currentSslStartDate == null) {
341                     startDateStringBuilder = new SpannableStringBuilder(startDateLabel);
342                 } else {
343                     startDateStringBuilder = new SpannableStringBuilder(startDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(currentSslStartDate));
344                 }
345
346                 if (currentSslEndDate == null) {
347                     endDateStringBuilder = new SpannableStringBuilder(endDateLabel);
348                 } else {
349                     endDateStringBuilder = new SpannableStringBuilder(endDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(currentSslEndDate));
350                 }
351             } else {  // Setup the pinned settings tab.
352                 // Create the string builders.
353                 ipAddressesStringBuilder = new SpannableStringBuilder(ipAddressesLabel + MainWebViewActivity.pinnedHostIpAddresses);
354                 issuedToCNameStringBuilder = new SpannableStringBuilder(cNameLabel + MainWebViewActivity.pinnedSslIssuedToCName);
355                 issuedToONameStringBuilder = new SpannableStringBuilder(oNameLabel + MainWebViewActivity.pinnedSslIssuedToOName);
356                 issuedToUNameStringBuilder = new SpannableStringBuilder(uNameLabel + MainWebViewActivity.pinnedSslIssuedToUName);
357                 issuedByCNameStringBuilder = new SpannableStringBuilder(cNameLabel + MainWebViewActivity.pinnedSslIssuedByCName);
358                 issuedByONameStringBuilder = new SpannableStringBuilder(oNameLabel + MainWebViewActivity.pinnedSslIssuedByOName);
359                 issuedByUNameStringBuilder = new SpannableStringBuilder(uNameLabel + MainWebViewActivity.pinnedSslIssuedByUName);
360
361                 // Set the dates if they aren't `null`.
362                 if (MainWebViewActivity.pinnedSslStartDate == null) {
363                     startDateStringBuilder = new SpannableStringBuilder(startDateLabel);
364                 } else {
365                     startDateStringBuilder = new SpannableStringBuilder(startDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG)
366                             .format(MainWebViewActivity.pinnedSslStartDate));
367                 }
368
369                 if (MainWebViewActivity.pinnedSslEndDate == null) {
370                     endDateStringBuilder = new SpannableStringBuilder(endDateLabel);
371                 } else {
372                     endDateStringBuilder = new SpannableStringBuilder(endDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(MainWebViewActivity.pinnedSslEndDate));
373                 }
374             }
375
376             // Create a red foreground color span.  The deprecated `getResources().getColor` must be used until the minimum API >= 23.
377             @SuppressWarnings("deprecation") ForegroundColorSpan redColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.red_a700));
378
379             // Create a blue foreground color span.
380             ForegroundColorSpan blueColorSpan;
381
382             // Set the blue color span according to the theme.  The deprecated `getResources().getColor` must be used until the minimum API >= 23.
383             if (MainWebViewActivity.darkTheme) {
384                 //noinspection deprecation
385                 blueColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.blue_400));
386             } else {
387                 //noinspection deprecation
388                 blueColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.blue_700));
389             }
390
391             // Set the domain name to be blue.
392             domainNameStringBuilder.setSpan(blueColorSpan, domainNameLabel.length(), domainNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
393
394             // Color coordinate the IP addresses if they are pinned.
395             if (pinnedIpAddresses) {
396                 if (MainWebViewActivity.currentHostIpAddresses.equals(MainWebViewActivity.pinnedHostIpAddresses)) {
397                     ipAddressesStringBuilder.setSpan(blueColorSpan, ipAddressesLabel.length(), ipAddressesStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
398                 } else {
399                     ipAddressesStringBuilder.setSpan(redColorSpan, ipAddressesLabel.length(), ipAddressesStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
400                 }
401             }
402
403             // Color coordinate the SSL certificate fields if they are pinned.
404             if (pinnedSslCertificate) {
405                 if (currentSslIssuedToCName.equals(MainWebViewActivity.pinnedSslIssuedToCName)) {
406                     issuedToCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), issuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
407                 } else {
408                     issuedToCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), issuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
409                 }
410
411                 if (currentSslIssuedToOName.equals(MainWebViewActivity.pinnedSslIssuedToOName)) {
412                     issuedToONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), issuedToONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
413                 } else {
414                     issuedToONameStringBuilder.setSpan(redColorSpan, oNameLabel.length(), issuedToONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
415                 }
416
417                 if (currentSslIssuedToUName.equals(MainWebViewActivity.pinnedSslIssuedToUName)) {
418                     issuedToUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), issuedToUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
419                 } else {
420                     issuedToUNameStringBuilder.setSpan(redColorSpan, uNameLabel.length(), issuedToUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
421                 }
422
423                 if (currentSslIssuedByCName.equals(MainWebViewActivity.pinnedSslIssuedByCName)) {
424                     issuedByCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), issuedByCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
425                 } else {
426                     issuedByCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), issuedByCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
427                 }
428
429                 if (currentSslIssuedByOName.equals(MainWebViewActivity.pinnedSslIssuedByOName)) {
430                     issuedByONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), issuedByONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
431                 } else {
432                     issuedByONameStringBuilder.setSpan(redColorSpan, oNameLabel.length(), issuedByONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
433                 }
434
435                 if (currentSslIssuedByUName.equals(MainWebViewActivity.pinnedSslIssuedByUName)) {
436                     issuedByUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), issuedByUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
437                 } else {
438                     issuedByUNameStringBuilder.setSpan(redColorSpan, uNameLabel.length(), issuedByUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
439                 }
440
441                 if ((currentSslStartDate != null) && currentSslStartDate.equals(MainWebViewActivity.pinnedSslStartDate)) {
442                     startDateStringBuilder.setSpan(blueColorSpan, startDateLabel.length(), startDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
443                 } else {
444                     startDateStringBuilder.setSpan(redColorSpan, startDateLabel.length(), startDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
445                 }
446
447                 if ((currentSslEndDate != null) && currentSslEndDate.equals(MainWebViewActivity.pinnedSslEndDate)) {
448                     endDateStringBuilder.setSpan(blueColorSpan, endDateLabel.length(), endDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
449                 } else {
450                     endDateStringBuilder.setSpan(redColorSpan, endDateLabel.length(), endDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
451                 }
452             }
453
454             // Display the strings.
455             domainNameTextView.setText(domainNameStringBuilder);
456             ipAddressesTextView.setText(ipAddressesStringBuilder);
457             issuedToCNameTextView.setText(issuedToCNameStringBuilder);
458             issuedToONameTextView.setText(issuedToONameStringBuilder);
459             issuedToUNameTextView.setText(issuedToUNameStringBuilder);
460             issuedByCNameTextView.setText(issuedByCNameStringBuilder);
461             issuedByONameTextView.setText(issuedByONameStringBuilder);
462             issuedByUNameTextView.setText(issuedByUNameStringBuilder);
463             startDateTextView.setText(startDateStringBuilder);
464             endDateTextView.setText(endDateStringBuilder);
465
466             // Display the tab.
467             container.addView(tabViewGroup);
468
469             // Make it so.
470             return tabViewGroup;
471         }
472     }
473 }