/*
- * Copyright © 2016-2018 Soren Stoutner <soren@stoutner.com>.
+ * Copyright © 2016-2019 Soren Stoutner <soren@stoutner.com>.
*
* This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
*
package com.stoutner.privacybrowser.dialogs;
import android.annotation.SuppressLint;
+import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.net.http.SslCertificate;
+import android.os.AsyncTask;
import android.os.Bundle;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import com.stoutner.privacybrowser.activities.MainWebViewActivity;
import com.stoutner.privacybrowser.R;
+import java.lang.ref.WeakReference;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
import java.text.DateFormat;
import java.util.Calendar;
import java.util.Date;
// The alert dialog must be shown before items in the layout can be modified.
alertDialog.show();
- // Get handles for the `TextViews`.
+ // Get handles for the text views.
TextView domainTextView = alertDialog.findViewById(R.id.domain);
+ TextView ipAddressesTextView = alertDialog.findViewById(R.id.ip_addresses);
TextView issuedToCNameTextView = alertDialog.findViewById(R.id.issued_to_cname);
TextView issuedToONameTextView = alertDialog.findViewById(R.id.issued_to_oname);
TextView issuedToUNameTextView = alertDialog.findViewById(R.id.issued_to_uname);
String startDateLabel = getString(R.string.start_date) + " ";
String endDateLabel = getString(R.string.end_date) + " ";
- // Parse `formattedUrlString` to a `URI`.
+ // Convert the formatted URL string to a URI.
Uri uri = Uri.parse(MainWebViewActivity.formattedUrlString);
- // Extract the domain name from `uri`.
+ // Extract the domain name from the URI.
String domainString = uri.getHost();
+ // Get the IP addresses.
+ new GetIpAddresses(getActivity(), alertDialog).execute(domainString);
+
// Get the SSL certificate.
SslCertificate sslCertificate = MainWebViewActivity.sslCertificate;
// Get the strings from the SSL certificate.
- String issuedToCNameString = sslCertificate.getIssuedTo().getCName();
- String issuedToONameString = sslCertificate.getIssuedTo().getOName();
- String issuedToUNameString = sslCertificate.getIssuedTo().getUName();
- String issuedByCNameString = sslCertificate.getIssuedBy().getCName();
- String issuedByONameString = sslCertificate.getIssuedBy().getOName();
- String issuedByUNameString = sslCertificate.getIssuedBy().getUName();
+ String issuedToCName = sslCertificate.getIssuedTo().getCName();
+ String issuedToOName = sslCertificate.getIssuedTo().getOName();
+ String issuedToUName = sslCertificate.getIssuedTo().getUName();
+ String issuedByCName = sslCertificate.getIssuedBy().getCName();
+ String issuedByOName = sslCertificate.getIssuedBy().getOName();
+ String issuedByUName = sslCertificate.getIssuedBy().getUName();
Date startDate = sslCertificate.getValidNotBeforeDate();
Date endDate = sslCertificate.getValidNotAfterDate();
- // Create a `SpannableStringBuilder` for each `TextView` that needs multiple colors of text.
+ // Create spannable string builders for each text view that needs multiple colors of text.
SpannableStringBuilder domainStringBuilder = new SpannableStringBuilder(domainLabel + domainString);
- SpannableStringBuilder issuedToCNameStringBuilder = new SpannableStringBuilder(cNameLabel + issuedToCNameString);
- SpannableStringBuilder issuedToONameStringBuilder = new SpannableStringBuilder(oNameLabel + issuedToONameString);
- SpannableStringBuilder issuedToUNameStringBuilder = new SpannableStringBuilder(uNameLabel + issuedToUNameString);
- SpannableStringBuilder issuedByCNameStringBuilder = new SpannableStringBuilder(cNameLabel + issuedByCNameString);
- SpannableStringBuilder issuedByONameStringBuilder = new SpannableStringBuilder(oNameLabel + issuedByONameString);
- SpannableStringBuilder issuedByUNameStringBuilder = new SpannableStringBuilder(uNameLabel + issuedByUNameString);
+ SpannableStringBuilder issuedToCNameStringBuilder = new SpannableStringBuilder(cNameLabel + issuedToCName);
+ SpannableStringBuilder issuedToONameStringBuilder = new SpannableStringBuilder(oNameLabel + issuedToOName);
+ SpannableStringBuilder issuedToUNameStringBuilder = new SpannableStringBuilder(uNameLabel + issuedToUName);
+ SpannableStringBuilder issuedByCNameStringBuilder = new SpannableStringBuilder(cNameLabel + issuedByCName);
+ SpannableStringBuilder issuedByONameStringBuilder = new SpannableStringBuilder(oNameLabel + issuedByOName);
+ SpannableStringBuilder issuedByUNameStringBuilder = new SpannableStringBuilder(uNameLabel + issuedByUName);
SpannableStringBuilder startDateStringBuilder = new SpannableStringBuilder(startDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(startDate));
SpannableStringBuilder endDateStringBuilder = new SpannableStringBuilder(endDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(endDate));
- // Create a red `ForegroundColorSpan`. We have to use the deprecated `getColor` until API >= 23.
+ // Create a red foreground color span. The deprecated `getColor` must be used until the minimum API >= 23.
@SuppressWarnings("deprecation") ForegroundColorSpan redColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.red_a700));
- // Create a blue `ForegroundColorSpan`.
+ // Create a blue foreground color span.
ForegroundColorSpan blueColorSpan;
- // Set `blueColorSpan` according to the theme. We have to use the deprecated `getColor()` until API >= 23.
+ // Set the blue color span according to the theme. The deprecated `getColor()` must be used until the minimum API >= 23.
if (MainWebViewActivity.darkTheme) {
//noinspection deprecation
blueColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.blue_400));
blueColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.blue_700));
}
+ // Remove the incorrect lint error that `.equals` might produce a NullPointerException.
+ assert domainString != null;
+
// Formet the `domainString` and `issuedToCName` colors.
- if (domainString.equals(issuedToCNameString)) { // `domainString` and `issuedToCNameString` match.
+ if (domainString.equals(issuedToCName)) { // `domainString` and `issuedToCName` match.
// Set the strings to be blue.
domainStringBuilder.setSpan(blueColorSpan, domainLabel.length(), domainStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
issuedToCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), issuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
- } else if(issuedToCNameString.startsWith("*.")){ // `issuedToCNameString` begins with a wildcard.
+ } else if(issuedToCName.startsWith("*.")){ // `issuedToCName` begins with a wildcard.
// Remove the initial `*.`.
- String baseCertificateDomain = issuedToCNameString.substring(2);
+ String baseCertificateDomain = issuedToCName.substring(2);
// Setup a copy of `domainString` to test subdomains.
String domainStringSubdomain = domainString;
issuedToCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), issuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
}
- // Setup the issued to and issued by spans to display the certificate information in blue. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
+ // Set the issued to and issued by spans to display the certificate information in blue. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
issuedToONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), issuedToONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
issuedToUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), issuedToUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
issuedByCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), issuedByCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
// Display the strings.
domainTextView.setText(domainStringBuilder);
+ ipAddressesTextView.setText(getString(R.string.ip_addresses));
issuedToCNameTextView.setText(issuedToCNameStringBuilder);
issuedToONameTextView.setText(issuedToONameStringBuilder);
issuedToUNameTextView.setText(issuedToUNameStringBuilder);
return alertDialog;
}
}
-}
+
+ // This must run asynchronously because it involves a network request. `String` declares the parameters. `Void` does not declare progress units. `String` contains the results.
+ private static class GetIpAddresses extends AsyncTask<String, Void, SpannableStringBuilder> {
+ // The weak references are used to determine if the activity or the alert dialog have disappeared while the AsyncTask is running.
+ private WeakReference<Activity> activityWeakReference;
+ private WeakReference<AlertDialog> alertDialogWeakReference;
+
+ GetIpAddresses(Activity activity, AlertDialog alertDialog) {
+ // Populate the weak references.
+ activityWeakReference = new WeakReference<>(activity);
+ alertDialogWeakReference = new WeakReference<>(alertDialog);
+ }
+
+ @Override
+ protected SpannableStringBuilder doInBackground(String... domainName) {
+ // Get handles for the activity and the alert dialog.
+ Activity activity = activityWeakReference.get();
+ AlertDialog alertDialog = alertDialogWeakReference.get();
+
+ // Abort if the activity or the dialog is gone.
+ if ((activity == null) || (activity.isFinishing()) || (alertDialog == null)) {
+ return new SpannableStringBuilder();
+ }
+
+ // Initialize an IP address string builder.
+ StringBuilder ipAddresses = new StringBuilder();
+
+ // Get an array with the IP addresses for the host.
+ try {
+ // Get an array with all the IP addresses for the domain.
+ InetAddress[] inetAddressesArray = InetAddress.getAllByName(domainName[0]);
+
+ // Add each IP address to the string builder.
+ for (InetAddress inetAddress : inetAddressesArray) {
+ if (ipAddresses.length() == 0) { // This is the first IP address.
+ // Add the IP Address to the string builder.
+ ipAddresses.append(inetAddress.getHostAddress());
+ } else { // This is not the first IP address.
+ // Add a line break to the string builder first.
+ ipAddresses.append("\n");
+
+ // Add the IP address to the string builder.
+ ipAddresses.append(inetAddress.getHostAddress());
+ }
+ }
+ } catch (UnknownHostException exception) {
+ // Do nothing.
+ }
+
+ // Set the label.
+ String ipAddressesLabel = activity.getString(R.string.ip_addresses) + " ";
+
+ // Create a spannable string builder.
+ SpannableStringBuilder ipAddressesStringBuilder = new SpannableStringBuilder(ipAddressesLabel + ipAddresses);
+
+ // Create a blue foreground color span.
+ ForegroundColorSpan blueColorSpan;
+
+ // Set the blue color span according to the theme. The deprecated `getColor()` must be used until the minimum API >= 23.
+ if (MainWebViewActivity.darkTheme) {
+ //noinspection deprecation
+ blueColorSpan = new ForegroundColorSpan(activity.getResources().getColor(R.color.blue_400));
+ } else {
+ //noinspection deprecation
+ blueColorSpan = new ForegroundColorSpan(activity.getResources().getColor(R.color.blue_700));
+ }
+
+ // Set the string builder to display the certificate information in blue. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
+ ipAddressesStringBuilder.setSpan(blueColorSpan, ipAddressesLabel.length(), ipAddressesStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+
+ // Return the formatted string.
+ return ipAddressesStringBuilder;
+ }
+
+ // `onPostExecute()` operates on the UI thread.
+ @Override
+ protected void onPostExecute(SpannableStringBuilder ipAddresses) {
+ // Get handles for the activity and the alert dialog.
+ Activity activity = activityWeakReference.get();
+ AlertDialog alertDialog = alertDialogWeakReference.get();
+
+ // Abort if the activity or the alert dialog is gone.
+ if ((activity == null) || (activity.isFinishing()) || (alertDialog == null)) {
+ return;
+ }
+
+ // Get a handle for the IP addresses text view.
+ TextView ipAddressesTextView = alertDialog.findViewById(R.id.ip_addresses);
+
+ // Populate the IP addresses text view.
+ ipAddressesTextView.setText(ipAddresses);
+ }
+ }
+}
\ No newline at end of file