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