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