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.View;
36 import android.view.ViewGroup;
37 import android.view.WindowManager;
38 import android.widget.TextView;
40 import com.google.android.material.tabs.TabLayout;
42 import com.stoutner.privacybrowser.R;
43 import com.stoutner.privacybrowser.activities.MainWebViewActivity;
44 import com.stoutner.privacybrowser.fragments.WebViewTabFragment;
45 import com.stoutner.privacybrowser.views.NestedScrollWebView;
46 import com.stoutner.privacybrowser.views.WrapVerticalContentViewPager;
47 import com.stoutner.privacybrowser.helpers.DomainsDatabaseHelper;
49 import java.text.DateFormat;
50 import java.util.ArrayList;
51 import java.util.Date;
53 import androidx.annotation.NonNull;
54 import androidx.fragment.app.DialogFragment; // The AndroidX dialog fragment must be used or an error is produced on API <=22.
55 import androidx.viewpager.widget.PagerAdapter;
57 public class PinnedMismatchDialog extends DialogFragment {
58 // Declare the class variables.
59 private PinnedMismatchListener pinnedMismatchListener;
60 private NestedScrollWebView nestedScrollWebView;
61 private String currentSslIssuedToCName;
62 private String currentSslIssuedToOName;
63 private String currentSslIssuedToUName;
64 private String currentSslIssuedByCName;
65 private String currentSslIssuedByOName;
66 private String currentSslIssuedByUName;
67 private Date currentSslStartDate;
68 private Date currentSslEndDate;
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(long webViewFragmentId) {
87 // Create an arguments bundle.
88 Bundle argumentsBundle = new Bundle();
90 // Store the WebView position in the bundle.
91 argumentsBundle.putLong("webview_fragment_id", webViewFragmentId);
93 // Create a new instance of the pinned mismatch dialog.
94 PinnedMismatchDialog pinnedMismatchDialog = new PinnedMismatchDialog();
96 // Add the arguments bundle to the new instance.
97 pinnedMismatchDialog.setArguments(argumentsBundle);
100 return pinnedMismatchDialog;
103 // `@SuppressLing("InflateParams")` removes the warning about using `null` as the parent view group when inflating the `AlertDialog`.
104 @SuppressLint("InflateParams")
107 public Dialog onCreateDialog(Bundle savedInstanceState) {
108 // Remove the incorrect lint warning below that `.getArguments().getInt()` might be null.
109 assert getArguments() != null;
111 // Get the current position of this WebView fragment.
112 int webViewPosition = MainWebViewActivity.webViewPagerAdapter.getPositionForId(getArguments().getLong("webview_fragment_id"));
114 // Get the WebView tab fragment.
115 WebViewTabFragment webViewTabFragment = MainWebViewActivity.webViewPagerAdapter.getPageFragment(webViewPosition);
117 // Get the fragment view.
118 View fragmentView = webViewTabFragment.getView();
120 // Remove the incorrect lint warning below that the fragment view might be null.
121 assert fragmentView != null;
123 // Get a handle for the current WebView.
124 nestedScrollWebView = fragmentView.findViewById(R.id.nestedscroll_webview);
126 // Use an alert dialog builder to create the alert dialog.
127 AlertDialog.Builder dialogBuilder;
129 // Set the style according to the theme.
130 if (MainWebViewActivity.darkTheme) {
131 // Set the dialog theme.
132 dialogBuilder = new AlertDialog.Builder(getActivity(), R.style.PrivacyBrowserAlertDialogDark);
134 // Set the dialog theme.
135 dialogBuilder = new AlertDialog.Builder(getActivity(), R.style.PrivacyBrowserAlertDialogLight);
138 // Set the favorite icon as the dialog icon if it exists.
139 if (MainWebViewActivity.favoriteIconBitmap.equals(MainWebViewActivity.favoriteIconDefaultBitmap)) { // There is no favorite icon.
140 // Set the icon according to the theme.
141 if (MainWebViewActivity.darkTheme) {
142 dialogBuilder.setIcon(R.drawable.ssl_certificate_enabled_dark);
144 dialogBuilder.setIcon(R.drawable.ssl_certificate_enabled_light);
146 } else { // There is a favorite icon.
147 // Create a drawable version of the favorite icon.
148 Drawable favoriteIconDrawable = new BitmapDrawable(getResources(), MainWebViewActivity.favoriteIconBitmap);
151 dialogBuilder.setIcon(favoriteIconDrawable);
154 // Setup the neutral button.
155 dialogBuilder.setNeutralButton(R.string.update, (DialogInterface dialog, int which) -> {
156 // Initialize the long date variables. If the date is null, a long value of `0` will be stored in the Domains database entry.
157 long currentSslStartDateLong = 0;
158 long currentSslEndDateLong = 0;
160 // Convert the `Dates` into `longs`.
161 if (currentSslStartDate != null) {
162 currentSslStartDateLong = currentSslStartDate.getTime();
165 if (currentSslEndDate != null) {
166 currentSslEndDateLong = currentSslEndDate.getTime();
169 // Initialize the database handler. The `0` specifies the database version, but that is ignored and set instead using a constant in `DomainsDatabaseHelper`.
170 DomainsDatabaseHelper domainsDatabaseHelper = new DomainsDatabaseHelper(getContext(), null, null, 0);
172 // Update the SSL certificate if it is pinned.
173 if (nestedScrollWebView.hasPinnedSslCertificate()) {
174 // Update the pinned SSL certificate in the domain database.
175 domainsDatabaseHelper.updatePinnedSslCertificate(nestedScrollWebView.getDomainSettingsDatabaseId(), currentSslIssuedToCName, currentSslIssuedToOName, currentSslIssuedToUName,
176 currentSslIssuedByCName, currentSslIssuedByOName, currentSslIssuedByUName, currentSslStartDateLong, currentSslEndDateLong);
178 // Update the pinned SSL certificate in the nested scroll WebView.
179 nestedScrollWebView.setPinnedSslCertificate(currentSslIssuedToCName, currentSslIssuedToOName, currentSslIssuedToUName, currentSslIssuedByCName, currentSslIssuedByOName, currentSslIssuedByUName,
180 currentSslStartDate, currentSslEndDate);
183 // Update the IP addresses if they are pinned.
184 if (nestedScrollWebView.hasPinnedIpAddresses()) {
185 // Update the pinned IP addresses in the domain database.
186 domainsDatabaseHelper.updatePinnedIpAddresses(nestedScrollWebView.getDomainSettingsDatabaseId(), nestedScrollWebView.getCurrentIpAddresses());
188 // Update the pinned IP addresses in the nested scroll WebView.
189 nestedScrollWebView.setPinnedIpAddresses(nestedScrollWebView.getCurrentIpAddresses());
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 // Remove the incorrect lint warning below that `getLayoutInflater()` might be null.
209 assert getActivity() != null;
211 // Set the layout. The parent view is `null` because it will be assigned by `AlertDialog`.
212 // For some reason, `getLayoutInflater()` without `getActivity()` produces an endless loop (probably a bug that will be fixed at some point in the future).
213 dialogBuilder.setView(getActivity().getLayoutInflater().inflate(R.layout.pinned_mismatch_linearlayout, null));
215 // Create an alert dialog from the alert dialog builder.
216 final AlertDialog alertDialog = dialogBuilder.create();
218 // Disable screenshots if not allowed.
219 if (!MainWebViewActivity.allowScreenshots) {
220 // Remove the warning below that `getWindow()` might be null.
221 assert alertDialog.getWindow() != null;
223 // Disable screenshots.
224 alertDialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE);
227 // Show the alert dialog so the items in the layout can be modified.
230 // Setup the view pager.
231 WrapVerticalContentViewPager wrapVerticalContentViewPager = alertDialog.findViewById(R.id.pinned_ssl_certificate_mismatch_viewpager);
232 wrapVerticalContentViewPager.setAdapter(new pagerAdapter());
234 // Setup the tab layout and connect it to the view pager.
235 TabLayout tabLayout = alertDialog.findViewById(R.id.pinned_ssl_certificate_mismatch_tablayout);
236 tabLayout.setupWithViewPager(wrapVerticalContentViewPager);
238 // `onCreateDialog()` requires the return of an `AlertDialog`.
242 private class pagerAdapter extends PagerAdapter {
244 public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
245 // Check to see if the `View` and the `Object` are the same.
246 return (view == object);
250 public int getCount() {
251 // There are two tabs.
256 public CharSequence getPageTitle(int position) {
257 // Return the current tab title.
258 if (position == 0) { // The current SSL certificate tab.
259 return getString(R.string.current);
260 } else { // The pinned SSL certificate tab.
261 return getString(R.string.pinned);
267 public Object instantiateItem(@NonNull ViewGroup container, int position) {
268 // Inflate the scroll view for this tab.
269 ViewGroup tabViewGroup = (ViewGroup) getLayoutInflater().inflate(R.layout.pinned_mismatch_scrollview, container, false);
271 // Get handles for the `TextViews`.
272 TextView domainNameTextView = tabViewGroup.findViewById(R.id.domain_name);
273 TextView ipAddressesTextView = tabViewGroup.findViewById(R.id.ip_addresses);
274 TextView issuedToCNameTextView = tabViewGroup.findViewById(R.id.issued_to_cname);
275 TextView issuedToONameTextView = tabViewGroup.findViewById(R.id.issued_to_oname);
276 TextView issuedToUNameTextView = tabViewGroup.findViewById(R.id.issued_to_uname);
277 TextView issuedByCNameTextView = tabViewGroup.findViewById(R.id.issued_by_cname);
278 TextView issuedByONameTextView = tabViewGroup.findViewById(R.id.issued_by_oname);
279 TextView issuedByUNameTextView = tabViewGroup.findViewById(R.id.issued_by_uname);
280 TextView startDateTextView = tabViewGroup.findViewById(R.id.start_date);
281 TextView endDateTextView = tabViewGroup.findViewById(R.id.end_date);
284 String domainNameLabel = getString(R.string.domain_label) + " ";
285 String ipAddressesLabel = getString(R.string.ip_addresses) + " ";
286 String cNameLabel = getString(R.string.common_name) + " ";
287 String oNameLabel = getString(R.string.organization) + " ";
288 String uNameLabel = getString(R.string.organizational_unit) + " ";
289 String startDateLabel = getString(R.string.start_date) + " ";
290 String endDateLabel = getString(R.string.end_date) + " ";
292 // Get a URI for the URL.
293 Uri currentUri = Uri.parse(MainWebViewActivity.formattedUrlString);
295 // Get the current host from the URI.
296 String domainName = currentUri.getHost();
298 // Get the current website SSL certificate.
299 SslCertificate sslCertificate = nestedScrollWebView.getCertificate();
301 // Extract the individual pieces of information from the current website SSL certificate if it is not null.
302 if (sslCertificate != null) {
303 currentSslIssuedToCName = sslCertificate.getIssuedTo().getCName();
304 currentSslIssuedToOName = sslCertificate.getIssuedTo().getOName();
305 currentSslIssuedToUName = sslCertificate.getIssuedTo().getUName();
306 currentSslIssuedByCName = sslCertificate.getIssuedBy().getCName();
307 currentSslIssuedByOName = sslCertificate.getIssuedBy().getOName();
308 currentSslIssuedByUName = sslCertificate.getIssuedBy().getUName();
309 currentSslStartDate = sslCertificate.getValidNotBeforeDate();
310 currentSslEndDate = sslCertificate.getValidNotAfterDate();
312 // Initialize the current website SSL certificate variables with blank information.
313 currentSslIssuedToCName = "";
314 currentSslIssuedToOName = "";
315 currentSslIssuedToUName = "";
316 currentSslIssuedByCName = "";
317 currentSslIssuedByOName = "";
318 currentSslIssuedByUName = "";
321 // Get the pinned SSL certificate.
322 ArrayList<Object> pinnedSslCertificateArrayList = nestedScrollWebView.getPinnedSslCertificate();
324 // Extract the arrays from the array list.
325 String[] pinnedSslCertificateStringArray = (String[]) pinnedSslCertificateArrayList.get(0);
326 Date[] pinnedSslCertificateDateArray = (Date[]) pinnedSslCertificateArrayList.get(1);
328 // Setup the domain name spannable string builder.
329 SpannableStringBuilder domainNameStringBuilder = new SpannableStringBuilder(domainNameLabel + domainName);
331 // Initialize the spannable string builders.
332 SpannableStringBuilder ipAddressesStringBuilder;
333 SpannableStringBuilder issuedToCNameStringBuilder;
334 SpannableStringBuilder issuedToONameStringBuilder;
335 SpannableStringBuilder issuedToUNameStringBuilder;
336 SpannableStringBuilder issuedByCNameStringBuilder;
337 SpannableStringBuilder issuedByONameStringBuilder;
338 SpannableStringBuilder issuedByUNameStringBuilder;
339 SpannableStringBuilder startDateStringBuilder;
340 SpannableStringBuilder endDateStringBuilder;
342 // Setup the spannable string builders for each tab.
343 if (position == 0) { // Setup the current settings tab.
344 // Create the string builders.
345 ipAddressesStringBuilder = new SpannableStringBuilder(ipAddressesLabel + nestedScrollWebView.getCurrentIpAddresses());
346 issuedToCNameStringBuilder = new SpannableStringBuilder(cNameLabel + currentSslIssuedToCName);
347 issuedToONameStringBuilder = new SpannableStringBuilder(oNameLabel + currentSslIssuedToOName);
348 issuedToUNameStringBuilder = new SpannableStringBuilder(uNameLabel + currentSslIssuedToUName);
349 issuedByCNameStringBuilder = new SpannableStringBuilder(cNameLabel + currentSslIssuedByCName);
350 issuedByONameStringBuilder = new SpannableStringBuilder(oNameLabel + currentSslIssuedByOName);
351 issuedByUNameStringBuilder = new SpannableStringBuilder(uNameLabel + currentSslIssuedByUName);
353 // Set the dates if they aren't `null`.
354 if (currentSslStartDate == null) {
355 startDateStringBuilder = new SpannableStringBuilder(startDateLabel);
357 startDateStringBuilder = new SpannableStringBuilder(startDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(currentSslStartDate));
360 if (currentSslEndDate == null) {
361 endDateStringBuilder = new SpannableStringBuilder(endDateLabel);
363 endDateStringBuilder = new SpannableStringBuilder(endDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(currentSslEndDate));
365 } else { // Setup the pinned settings tab.
366 // Create the string builders.
367 ipAddressesStringBuilder = new SpannableStringBuilder(ipAddressesLabel + nestedScrollWebView.getPinnedIpAddresses());
368 issuedToCNameStringBuilder = new SpannableStringBuilder(cNameLabel + pinnedSslCertificateStringArray[0]);
369 issuedToONameStringBuilder = new SpannableStringBuilder(oNameLabel + pinnedSslCertificateStringArray[1]);
370 issuedToUNameStringBuilder = new SpannableStringBuilder(uNameLabel + pinnedSslCertificateStringArray[2]);
371 issuedByCNameStringBuilder = new SpannableStringBuilder(cNameLabel + pinnedSslCertificateStringArray[3]);
372 issuedByONameStringBuilder = new SpannableStringBuilder(oNameLabel + pinnedSslCertificateStringArray[4]);
373 issuedByUNameStringBuilder = new SpannableStringBuilder(uNameLabel + pinnedSslCertificateStringArray[5]);
375 // Set the dates if they aren't `null`.
376 if (pinnedSslCertificateDateArray[0] == null) {
377 startDateStringBuilder = new SpannableStringBuilder(startDateLabel);
379 startDateStringBuilder = new SpannableStringBuilder(startDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(pinnedSslCertificateDateArray[0]));
382 if (pinnedSslCertificateDateArray[1] == null) {
383 endDateStringBuilder = new SpannableStringBuilder(endDateLabel);
385 endDateStringBuilder = new SpannableStringBuilder(endDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(pinnedSslCertificateDateArray[1]));
389 // Create a red foreground color span. The deprecated `getResources().getColor` must be used until the minimum API >= 23.
390 @SuppressWarnings("deprecation") ForegroundColorSpan redColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.red_a700));
392 // Create a blue foreground color span.
393 ForegroundColorSpan blueColorSpan;
395 // Set the blue color span according to the theme. The deprecated `getResources().getColor` must be used until the minimum API >= 23.
396 if (MainWebViewActivity.darkTheme) {
397 //noinspection deprecation
398 blueColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.blue_400));
400 //noinspection deprecation
401 blueColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.blue_700));
404 // Set the domain name to be blue.
405 domainNameStringBuilder.setSpan(blueColorSpan, domainNameLabel.length(), domainNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
407 // Color coordinate the IP addresses if they are pinned.
408 if (nestedScrollWebView.hasPinnedIpAddresses()) {
409 if (nestedScrollWebView.getCurrentIpAddresses().equals(nestedScrollWebView.getPinnedIpAddresses())) {
410 ipAddressesStringBuilder.setSpan(blueColorSpan, ipAddressesLabel.length(), ipAddressesStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
412 ipAddressesStringBuilder.setSpan(redColorSpan, ipAddressesLabel.length(), ipAddressesStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
416 // Color coordinate the SSL certificate fields if they are pinned.
417 if (nestedScrollWebView.hasPinnedSslCertificate()) {
418 if (currentSslIssuedToCName.equals(pinnedSslCertificateStringArray[0])) {
419 issuedToCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), issuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
421 issuedToCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), issuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
424 if (currentSslIssuedToOName.equals(pinnedSslCertificateStringArray[1])) {
425 issuedToONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), issuedToONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
427 issuedToONameStringBuilder.setSpan(redColorSpan, oNameLabel.length(), issuedToONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
430 if (currentSslIssuedToUName.equals(pinnedSslCertificateStringArray[2])) {
431 issuedToUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), issuedToUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
433 issuedToUNameStringBuilder.setSpan(redColorSpan, uNameLabel.length(), issuedToUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
436 if (currentSslIssuedByCName.equals(pinnedSslCertificateStringArray[3])) {
437 issuedByCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), issuedByCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
439 issuedByCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), issuedByCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
442 if (currentSslIssuedByOName.equals(pinnedSslCertificateStringArray[4])) {
443 issuedByONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), issuedByONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
445 issuedByONameStringBuilder.setSpan(redColorSpan, oNameLabel.length(), issuedByONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
448 if (currentSslIssuedByUName.equals(pinnedSslCertificateStringArray[5])) {
449 issuedByUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), issuedByUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
451 issuedByUNameStringBuilder.setSpan(redColorSpan, uNameLabel.length(), issuedByUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
454 if ((currentSslStartDate != null) && currentSslStartDate.equals(pinnedSslCertificateDateArray[0])) {
455 startDateStringBuilder.setSpan(blueColorSpan, startDateLabel.length(), startDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
457 startDateStringBuilder.setSpan(redColorSpan, startDateLabel.length(), startDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
460 if ((currentSslEndDate != null) && currentSslEndDate.equals(pinnedSslCertificateDateArray[1])) {
461 endDateStringBuilder.setSpan(blueColorSpan, endDateLabel.length(), endDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
463 endDateStringBuilder.setSpan(redColorSpan, endDateLabel.length(), endDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
467 // Display the strings.
468 domainNameTextView.setText(domainNameStringBuilder);
469 ipAddressesTextView.setText(ipAddressesStringBuilder);
470 issuedToCNameTextView.setText(issuedToCNameStringBuilder);
471 issuedToONameTextView.setText(issuedToONameStringBuilder);
472 issuedToUNameTextView.setText(issuedToUNameStringBuilder);
473 issuedByCNameTextView.setText(issuedByCNameStringBuilder);
474 issuedByONameTextView.setText(issuedByONameStringBuilder);
475 issuedByUNameTextView.setText(issuedByUNameStringBuilder);
476 startDateTextView.setText(startDateStringBuilder);
477 endDateTextView.setText(endDateStringBuilder);
480 container.addView(tabViewGroup);