2 * Copyright © 2017-2019 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.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;
41 import com.google.android.material.tabs.TabLayout;
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;
48 import java.text.DateFormat;
49 import java.util.Date;
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;
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;
70 // The public interface is used to send information back to the parent activity.
71 public interface PinnedMismatchListener {
72 void onPinnedMismatchBack();
74 void onPinnedMismatchProceed();
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);
82 // Get a handle for `PinnedSslCertificateMismatchListener` from the launching context.
83 pinnedMismatchListener = (PinnedMismatchListener) context;
86 public static PinnedMismatchDialog displayDialog(int domainSettingsDatabaseId, boolean pinnedSslCertificate, boolean pinnedIpAddresses) {
87 // Create an arguments bundle.
88 Bundle argumentsBundle = new Bundle();
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);
95 // Add the arguments bundle to this instance of `PinnedMismatchDialog`.
96 PinnedMismatchDialog thisPinnedMismatchDialog = new PinnedMismatchDialog();
97 thisPinnedMismatchDialog.setArguments(argumentsBundle);
98 return thisPinnedMismatchDialog;
101 // `@SuppressLing("InflateParams")` removes the warning about using `null` as the parent view group when inflating the `AlertDialog`.
102 @SuppressLint("InflateParams")
105 public Dialog onCreateDialog(Bundle savedInstanceState) {
106 // Remove the incorrect lint warning that `getActivity()` might be null.
107 assert getActivity() != null;
109 // Get the activity's layout inflater.
110 layoutInflater = getActivity().getLayoutInflater();
112 // Use an alert dialog builder to create the alert dialog.
113 AlertDialog.Builder dialogBuilder;
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);
120 // Set the dialog theme.
121 dialogBuilder = new AlertDialog.Builder(getActivity(), R.style.PrivacyBrowserAlertDialogLight);
124 // Remove the incorrect lint warning below that `.getArguments.getBoolean()` might be null.
125 assert getArguments() != null;
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");
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);
138 dialogBuilder.setIcon(R.drawable.ssl_certificate_enabled_light);
140 } else { // There is a favorite icon.
141 // Create a drawable version of the favorite icon.
142 Drawable favoriteIconDrawable = new BitmapDrawable(getResources(), MainWebViewActivity.favoriteIconBitmap);
145 dialogBuilder.setIcon(favoriteIconDrawable);
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;
154 // Convert the `Dates` into `longs`.
155 if (currentSslStartDate != null) {
156 currentSslStartDateLong = currentSslStartDate.getTime();
159 if (currentSslEndDate != null) {
160 currentSslEndDateLong = currentSslEndDate.getTime();
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);
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);
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;
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);
188 // Update the pinned IP addresses class variable to match the information that is now in the database.
189 MainWebViewActivity.pinnedHostIpAddresses = MainWebViewActivity.currentHostIpAddresses;
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();
199 // Setup the positive button.
200 dialogBuilder.setPositiveButton(R.string.proceed, (DialogInterface dialog, int which) -> {
201 // Call the `onSslMismatchProceed` public interface.
202 pinnedMismatchListener.onPinnedMismatchProceed();
206 dialogBuilder.setTitle(R.string.pinned_mismatch);
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));
211 // Create an alert dialog from the alert dialog builder.
212 final AlertDialog alertDialog = dialogBuilder.create();
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;
219 // Disable screenshots.
220 alertDialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE);
223 // Show the alert dialog so the items in the layout can be modified.
226 // Setup the view pager.
227 WrapVerticalContentViewPager wrapVerticalContentViewPager = alertDialog.findViewById(R.id.pinned_ssl_certificate_mismatch_viewpager);
228 wrapVerticalContentViewPager.setAdapter(new pagerAdapter());
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);
234 // `onCreateDialog()` requires the return of an `AlertDialog`.
238 private class pagerAdapter extends PagerAdapter {
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);
246 public int getCount() {
247 // There are two tabs.
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);
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);
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);
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) + " ";
288 // Get a URI for the URL.
289 Uri currentUri = Uri.parse(MainWebViewActivity.formattedUrlString);
291 // Get the current host from the URI.
292 String domainName = currentUri.getHost();
294 // Get the current website SSL certificate.
295 SslCertificate sslCertificate = MainWebViewActivity.sslCertificate;
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();
308 // Initialize the current website SSL certificate variables with blank information.
309 currentSslIssuedToCName = "";
310 currentSslIssuedToOName = "";
311 currentSslIssuedToUName = "";
312 currentSslIssuedByCName = "";
313 currentSslIssuedByOName = "";
314 currentSslIssuedByUName = "";
317 // Setup the domain name spannable string builder.
318 SpannableStringBuilder domainNameStringBuilder = new SpannableStringBuilder(domainNameLabel + domainName);
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;
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);
342 // Set the dates if they aren't `null`.
343 if (currentSslStartDate == null) {
344 startDateStringBuilder = new SpannableStringBuilder(startDateLabel);
346 startDateStringBuilder = new SpannableStringBuilder(startDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(currentSslStartDate));
349 if (currentSslEndDate == null) {
350 endDateStringBuilder = new SpannableStringBuilder(endDateLabel);
352 endDateStringBuilder = new SpannableStringBuilder(endDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(currentSslEndDate));
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);
364 // Set the dates if they aren't `null`.
365 if (MainWebViewActivity.pinnedSslStartDate == null) {
366 startDateStringBuilder = new SpannableStringBuilder(startDateLabel);
368 startDateStringBuilder = new SpannableStringBuilder(startDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG)
369 .format(MainWebViewActivity.pinnedSslStartDate));
372 if (MainWebViewActivity.pinnedSslEndDate == null) {
373 endDateStringBuilder = new SpannableStringBuilder(endDateLabel);
375 endDateStringBuilder = new SpannableStringBuilder(endDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(MainWebViewActivity.pinnedSslEndDate));
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));
382 // Create a blue foreground color span.
383 ForegroundColorSpan blueColorSpan;
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));
390 //noinspection deprecation
391 blueColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.blue_700));
394 // Set the domain name to be blue.
395 domainNameStringBuilder.setSpan(blueColorSpan, domainNameLabel.length(), domainNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
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);
402 ipAddressesStringBuilder.setSpan(redColorSpan, ipAddressesLabel.length(), ipAddressesStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
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);
411 issuedToCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), issuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
414 if (currentSslIssuedToOName.equals(MainWebViewActivity.pinnedSslIssuedToOName)) {
415 issuedToONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), issuedToONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
417 issuedToONameStringBuilder.setSpan(redColorSpan, oNameLabel.length(), issuedToONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
420 if (currentSslIssuedToUName.equals(MainWebViewActivity.pinnedSslIssuedToUName)) {
421 issuedToUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), issuedToUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
423 issuedToUNameStringBuilder.setSpan(redColorSpan, uNameLabel.length(), issuedToUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
426 if (currentSslIssuedByCName.equals(MainWebViewActivity.pinnedSslIssuedByCName)) {
427 issuedByCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), issuedByCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
429 issuedByCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), issuedByCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
432 if (currentSslIssuedByOName.equals(MainWebViewActivity.pinnedSslIssuedByOName)) {
433 issuedByONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), issuedByONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
435 issuedByONameStringBuilder.setSpan(redColorSpan, oNameLabel.length(), issuedByONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
438 if (currentSslIssuedByUName.equals(MainWebViewActivity.pinnedSslIssuedByUName)) {
439 issuedByUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), issuedByUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
441 issuedByUNameStringBuilder.setSpan(redColorSpan, uNameLabel.length(), issuedByUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
444 if ((currentSslStartDate != null) && currentSslStartDate.equals(MainWebViewActivity.pinnedSslStartDate)) {
445 startDateStringBuilder.setSpan(blueColorSpan, startDateLabel.length(), startDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
447 startDateStringBuilder.setSpan(redColorSpan, startDateLabel.length(), startDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
450 if ((currentSslEndDate != null) && currentSslEndDate.equals(MainWebViewActivity.pinnedSslEndDate)) {
451 endDateStringBuilder.setSpan(blueColorSpan, endDateLabel.length(), endDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
453 endDateStringBuilder.setSpan(redColorSpan, endDateLabel.length(), endDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
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);
470 container.addView(tabViewGroup);