<w>panopticlick</w>
<w>parameterized</w>
<w>parentfolder</w>
+ <w>pinnedsslcertificate</w>
<w>programatically</w>
<w>proxying</w>
<w>qwant</w>
<w>snackbar</w>
<w>snackbars</w>
<w>softkeyboard</w>
+ <w>sslenddate</w>
+ <w>sslissuedbycommonname</w>
+ <w>sslissuedbyorganization</w>
+ <w>sslissuedbyorganizationalunit</w>
+ <w>sslissuedtocommonname</w>
+ <w>sslissuedtoorganization</w>
+ <w>sslissuedtoorganizationalunit</w>
+ <w>sslstartdate</w>
<w>subdomain</w>
<w>subdomains</w>
<w>subfolders</w>
<w>uidh</w>
<w>uids</w>
<w>uname</w>
+ <w>uncheck</w>
<w>useragent</w>
<w>useragentname</w>
<w>useragentstring</w>
<p><img class="icon" src="../en/images/ic_vertical_align_bottom.png"> ic_vertical_align_bottom.</p>
<p><img class="icon" src="../en/images/ic_vertical_align_top.png"> ic_vertical_align_top.</p>
<p><img class="icon" src="../en/images/ic_visibility_off.png"> ic_visibility_off.</p>
+ <p><img class="icon" src="../en/images/ic_vpn_lock.png"> ic_vpn_lock.</p>
<p><img class="icon" src="../en/images/ic_web.png"> ic_web.</p>
<hr/>
<p><img class="icon" src="images/ic_vertical_align_bottom.png"> ic_vertical_align_bottom.</p>
<p><img class="icon" src="images/ic_vertical_align_top.png"> ic_vertical_align_top.</p>
<p><img class="icon" src="images/ic_visibility_off.png"> ic_visibility_off.</p>
+ <p><img class="icon" src="images/ic_vpn_lock.png"> ic_vpn_lock.</p>
<p><img class="icon" src="images/ic_web.png"> ic_web.</p>
<hr/>
<p><img class="icon" src="../en/images/ic_vertical_align_bottom.png"> ic_vertical_align_bottom.</p>
<p><img class="icon" src="../en/images/ic_vertical_align_top.png"> ic_vertical_align_top.</p>
<p><img class="icon" src="../en/images/ic_visibility_off.png"> ic_visibility_off.</p>
+ <p><img class="icon" src="../en/images/ic_vpn_lock.png"> ic_vpn_lock.</p>
<p><img class="icon" src="../en/images/ic_web.png"> ic_web.</p>
<hr/>
<p><img class="icon" src="../en/images/ic_vertical_align_bottom.png"> ic_vertical_align_bottom.</p>
<p><img class="icon" src="../en/images/ic_vertical_align_top.png"> ic_vertical_align_top.</p>
<p><img class="icon" src="../en/images/ic_visibility_off.png"> ic_visibility_off.</p>
+ <p><img class="icon" src="../en/images/ic_vpn_lock.png"> ic_vpn_lock.</p>
<p><img class="icon" src="../en/images/ic_web.png"> ic_web.</p>
<hr/>
import android.content.Context;
import android.database.Cursor;
+import android.net.http.SslCertificate;
import android.os.Bundle;
import android.os.Handler;
import android.support.design.widget.FloatingActionButton;
import android.widget.CursorAdapter;
import android.widget.EditText;
import android.widget.ListView;
+import android.widget.RadioButton;
import android.widget.Spinner;
import android.widget.Switch;
import android.widget.TextView;
EditText customUserAgentEditText = (EditText) findViewById(R.id.domain_settings_custom_user_agent_edittext);
Spinner fontSizeSpinner = (Spinner) findViewById(R.id.domain_settings_font_size_spinner);
Spinner displayWebpageImagesSpinner = (Spinner) findViewById(R.id.domain_settings_display_webpage_images_spinner);
+ Switch pinnedSslCertificateSwitch = (Switch) findViewById(R.id.domain_settings_pinned_ssl_certificate_switch);
+ RadioButton savedSslCertificateRadioButton = (RadioButton) findViewById(R.id.saved_ssl_certificate_radiobutton);
+ RadioButton currentWebsiteCertificateRadioButton = (RadioButton) findViewById(R.id.current_website_certificate_radiobutton);
// Extract the data for the domain settings.
String domainNameString = domainNameEditText.getText().toString();
int userAgentPositionInt = userAgentSpinner.getSelectedItemPosition();
int fontSizePositionInt = fontSizeSpinner.getSelectedItemPosition();
int displayWebpageImagesInt = displayWebpageImagesSpinner.getSelectedItemPosition();
+ boolean pinnedSslCertificate = pinnedSslCertificateSwitch.isChecked();
// Get the data for the `Spinners` from the entry values string arrays.
String userAgentString = getResources().getStringArray(R.array.domain_settings_user_agent_entry_values)[userAgentPositionInt];
}
// Save the domain settings.
- domainsDatabaseHelper.saveDomain(currentDomainDatabaseId, domainNameString, javaScriptEnabledBoolean, firstPartyCookiesEnabledBoolean, thirdPartyCookiesEnabledBoolean, domStorageEnabledEnabledBoolean, formDataEnabledBoolean, userAgentString, fontSizeInt,
- displayWebpageImagesInt);
+ if (savedSslCertificateRadioButton.isChecked()) { // The current certificate is being used.
+ // Update the database except for the certificate.
+ domainsDatabaseHelper.updateDomainExceptCertificate(DomainsActivity.currentDomainDatabaseId, domainNameString, javaScriptEnabledBoolean, firstPartyCookiesEnabledBoolean, thirdPartyCookiesEnabledBoolean, domStorageEnabledEnabledBoolean,
+ formDataEnabledBoolean, userAgentString, fontSizeInt, displayWebpageImagesInt, pinnedSslCertificate);
+ } else if (currentWebsiteCertificateRadioButton.isChecked()) { // The certificate is being updated with the current website certificate.
+ // Get the current website SSL certificate.
+ SslCertificate currentWebsiteSslCertificate = MainWebViewActivity.sslCertificate;
+
+ // Store the values from the SSL certificate.
+ String issuedToCommonName = currentWebsiteSslCertificate.getIssuedTo().getCName();
+ String issuedToOrganization = currentWebsiteSslCertificate.getIssuedTo().getOName();
+ String issuedToOrganizationalUnit = currentWebsiteSslCertificate.getIssuedTo().getUName();
+ String issuedByCommonName = currentWebsiteSslCertificate.getIssuedBy().getCName();
+ String issuedByOrganization = currentWebsiteSslCertificate.getIssuedBy().getOName();
+ String issuedByOrganizationalUnit = currentWebsiteSslCertificate.getIssuedBy().getUName();
+ long startDateLong = currentWebsiteSslCertificate.getValidNotBeforeDate().getTime();
+ long endDateLong = currentWebsiteSslCertificate.getValidNotAfterDate().getTime();
+
+ // Update the database.
+ domainsDatabaseHelper.updateDomainWithCertificate(currentDomainDatabaseId, domainNameString, javaScriptEnabledBoolean, firstPartyCookiesEnabledBoolean, thirdPartyCookiesEnabledBoolean, domStorageEnabledEnabledBoolean, formDataEnabledBoolean,
+ userAgentString, fontSizeInt, displayWebpageImagesInt, pinnedSslCertificate, issuedToCommonName, issuedToOrganization, issuedToOrganizationalUnit, issuedByCommonName, issuedByOrganization, issuedByOrganizationalUnit, startDateLong,
+ endDateLong);
+ } else { // No certificate is selected.
+ // Update the database, with PINNED_SSL_CERTIFICATE set to false.
+ domainsDatabaseHelper.updateDomainExceptCertificate(currentDomainDatabaseId, domainNameString, javaScriptEnabledBoolean, firstPartyCookiesEnabledBoolean, thirdPartyCookiesEnabledBoolean, domStorageEnabledEnabledBoolean, formDataEnabledBoolean,
+ userAgentString, fontSizeInt, displayWebpageImagesInt, false);
+ }
}
private void populateDomainsListView(final int highlightedDomainDatabaseId) {
import com.stoutner.privacybrowser.R;
import com.stoutner.privacybrowser.dialogs.CreateHomeScreenShortcutDialog;
import com.stoutner.privacybrowser.dialogs.DownloadImageDialog;
+import com.stoutner.privacybrowser.dialogs.PinnedSslCertificateMismatchDialog;
import com.stoutner.privacybrowser.dialogs.UrlHistoryDialog;
import com.stoutner.privacybrowser.dialogs.ViewSslCertificateDialog;
import com.stoutner.privacybrowser.helpers.DomainsDatabaseHelper;
import java.net.URL;
import java.net.URLDecoder;
import java.net.URLEncoder;
+import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
// We need to use AppCompatActivity from android.support.v7.app.AppCompatActivity to have access to the SupportActionBar until the minimum API is >= 21.
public class MainWebViewActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener, CreateHomeScreenShortcutDialog.CreateHomeScreenSchortcutListener,
- SslCertificateErrorDialog.SslCertificateErrorListener, DownloadFileDialog.DownloadFileListener, DownloadImageDialog.DownloadImageListener, UrlHistoryDialog.UrlHistoryListener {
+ PinnedSslCertificateMismatchDialog.PinnedSslCertificateMismatchListener, SslCertificateErrorDialog.SslCertificateErrorListener, DownloadFileDialog.DownloadFileListener, DownloadImageDialog.DownloadImageListener, UrlHistoryDialog.UrlHistoryListener {
// `darkTheme` is public static so it can be accessed from `AboutActivity`, `GuideActivity`, `AddDomainDialog`, `SettingsActivity`, `DomainsActivity`, `DomainsListFragment`, `BookmarksActivity`, `BookmarksDatabaseViewActivity`,
// `CreateBookmarkDialog`, `CreateBookmarkFolderDialog`, `DownloadFileDialog`, `DownloadImageDialog`, `EditBookmarkDialog`, `EditBookmarkFolderDialog`, `MoveToFolderDialog`, `SslCertificateErrorDialog`, `UrlHistoryDialog`, `ViewSslCertificateDialog`,
// `CreateHomeScreenShortcutDialog`, and `OrbotProxyHelper`. It is also used in `onCreate()`, `applyAppSettings()`, `applyDomainSettings()`, and `updatePrivacyIcons()`.
public static boolean darkTheme;
- // `favoriteIconBitmap` is public static so it can be accessed from `CreateHomeScreenShortcutDialog`, `BookmarksActivity`, `CreateBookmarkDialog`, `CreateBookmarkFolderDialog`, `EditBookmarkDialog`, `EditBookmarkFolderDialog`, `ViewSslCertificateDialog`.
- // It is also used in `onCreate()`, `onCreateHomeScreenShortcutCreate()`, and `applyDomainSettings`.
+ // `favoriteIconBitmap` is public static so it can be accessed from `CreateHomeScreenShortcutDialog`, `BookmarksActivity`, `CreateBookmarkDialog`, `CreateBookmarkFolderDialog`, `EditBookmarkDialog`, `EditBookmarkFolderDialog`,
+ // and `ViewSslCertificateDialog`. It is also used in `onCreate()`, `onCreateHomeScreenShortcutCreate()`, and `applyDomainSettings`.
public static Bitmap favoriteIconBitmap;
// `formattedUrlString` is public static so it can be accessed from `BookmarksActivity`, `CreateBookmarkDialog`, and `AddDomainDialog`.
// It is also used in `onCreate()`, `onOptionsItemSelected()`, `onNavigationItemSelected()`, `onCreateHomeScreenShortcutCreate()`, and `loadUrlFromTextBox()`.
public static String formattedUrlString;
- // `sslCertificate` is public static so it can be accessed from `ViewSslCertificateDialog`. It is also used in `onCreate()`.
+ // `sslCertificate` is public static so it can be accessed from `DomainsActivity`, `DomainsListFragment`, `DomainSettingsFragment`, `PinnedSslCertificateMismatchDialog`, and `ViewSslCertificateDialog`. It is also used in `onCreate()`.
public static SslCertificate sslCertificate;
// `orbotStatus` is public static so it can be accessed from `OrbotProxyHelper`. It is also used in `onCreate()`.
// `reloadOnRestartBoolean` is public static so it can be accessed from `SettingsFragment`. It is also used in `onRestart()`
public static boolean reloadOnRestartBoolean;
+ // The pinned domain SSL Certificate variables are public static so they can be accessed from `PinnedSslCertificateMismatchDialog`. They are also used in `onCreate()` and `applyDomainSettings()`.
+ public static int domainSettingsDatabaseId;
+ public static boolean pinnedDomainSslCertificate;
+ public static String pinnedDomainSslIssuedToCNameString;
+ public static String pinnedDomainSslIssuedToONameString;
+ public static String pinnedDomainSslIssuedToUNameString;
+ public static String pinnedDomainSslIssuedByCNameString;
+ public static String pinnedDomainSslIssuedByONameString;
+ public static String pinnedDomainSslIssuedByUNameString;
+ public static Date pinnedDomainSslStartDate;
+ public static Date pinnedDomainSslEndDate;
+
// `appBar` is used in `onCreate()`, `onOptionsItemSelected()`, `closeFindOnPage()`, and `applyAppSettings()`.
private ActionBar appBar;
- // `navigatingHistory` is used in `onCreate()`, `onNavigationItemSelected()`, and `applyDomainSettings()`.
+ // `navigatingHistory` is used in `onCreate()`, `onNavigationItemSelected()`, `onSslMismatchBack()`, and `applyDomainSettings()`.
private boolean navigatingHistory;
// `favoriteIconDefaultBitmap` is used in `onCreate()` and `applyDomainSettings`.
private CoordinatorLayout rootCoordinatorLayout;
// `mainWebView` is used in `onCreate()`, `onPrepareOptionsMenu()`, `onOptionsItemSelected()`, `onNavigationItemSelected()`, `onRestart()`, `onCreateContextMenu()`, `findPreviousOnPage()`, `findNextOnPage()`, `closeFindOnPage()`, `loadUrlFromTextBox()`
- // and `setDisplayWebpageImages()`.
+ // `onSslMismatchBack()`, and `setDisplayWebpageImages()`.
private WebView mainWebView;
// `fullScreenVideoFrameLayout` is used in `onCreate()` and `onConfigurationChanged()`.
// `translucentNavigationBarOnFullscreen` is used in `onCreate()` and `applyAppSettings()`.
private boolean translucentNavigationBarOnFullscreen;
- // `currentDomainName` is used in `onCreate()`, `onNavigationItemSelected()`, and `applyDomainSettings()`.
+ // `currentDomainName` is used in `onCreate()`, `onNavigationItemSelected()`, `onSslMismatchProceed()`, and `applyDomainSettings()`.
private String currentDomainName;
+ // `ignorePinnedSslCertificateForDomain` is used in `onCreate()`, `onSslMismatchProceed()`, and `applyDomainSettings()`.
+ private boolean ignorePinnedSslCertificate;
+
// `waitingForOrbot` is used in `onCreate()` and `applyAppSettings()`.
private boolean waitingForOrbot;
// `urlIsLoading` is used in `onCreate()`, `loadUrl()`, and `applyDomainSettings()`.
private boolean urlIsLoading;
+
@Override
// Remove Android Studio's warning about the dangers of using SetJavaScriptEnabled. The whole premise of Privacy Browser is built around an understanding of these dangers.
@SuppressLint("SetJavaScriptEnabled")
}
}
- // Store the SSL certificate so it can be accessed from `ViewSslCertificateDialog`.
+ // Store the SSL certificate so it can be accessed from `ViewSslCertificateDialog` and `PinnedSslCertificateMismatchDialog`.
sslCertificate = mainWebView.getCertificate();
+
+ // Check the current website SSL certificate against the pinned SSL certificate if there is a pinned SSL certificate the user has not chosen to ignore it for this session.
+ if (pinnedDomainSslCertificate && !ignorePinnedSslCertificate) {
+ // Initialize the current SSL certificate variables.
+ String currentWebsiteIssuedToCName = "";
+ String currentWebsiteIssuedToOName = "";
+ String currentWebsiteIssuedToUName = "";
+ String currentWebsiteIssuedByCName = "";
+ String currentWebsiteIssuedByOName = "";
+ String currentWebsiteIssuedByUName = "";
+ Date currentWebsiteSslStartDate = null;
+ Date currentWebsiteSslEndDate = null;
+
+
+ // Extract the individual pieces of information from the current website SSL certificate if it is not null.
+ if (sslCertificate != null) {
+ currentWebsiteIssuedToCName = sslCertificate.getIssuedTo().getCName();
+ currentWebsiteIssuedToOName = sslCertificate.getIssuedTo().getOName();
+ currentWebsiteIssuedToUName = sslCertificate.getIssuedTo().getUName();
+ currentWebsiteIssuedByCName = sslCertificate.getIssuedBy().getCName();
+ currentWebsiteIssuedByOName = sslCertificate.getIssuedBy().getOName();
+ currentWebsiteIssuedByUName = sslCertificate.getIssuedBy().getUName();
+ currentWebsiteSslStartDate = sslCertificate.getValidNotBeforeDate();
+ currentWebsiteSslEndDate = sslCertificate.getValidNotAfterDate();
+ }
+
+ // Initialize `String` variables to store the SSL certificate dates. `Strings` are needed to compare the values below, which doesn't work with `Dates` if they are `null`.
+ String currentWebsiteSslStartDateString = "";
+ String currentWebsiteSslEndDateString = "";
+ String pinnedDomainSslStartDateString = "";
+ String pinnedDomainSslEndDateString = "";
+
+ // Convert the `Dates` to `Strings` if they are not `null`.
+ if (currentWebsiteSslStartDate != null) {
+ currentWebsiteSslStartDateString = currentWebsiteSslStartDate.toString();
+ }
+
+ if (currentWebsiteSslEndDate != null) {
+ currentWebsiteSslEndDateString = currentWebsiteSslEndDate.toString();
+ }
+
+ if (pinnedDomainSslStartDate != null) {
+ pinnedDomainSslStartDateString = pinnedDomainSslStartDate.toString();
+ }
+
+ if (pinnedDomainSslEndDate != null) {
+ pinnedDomainSslEndDateString = pinnedDomainSslEndDate.toString();
+ }
+
+ // Check to see if the pinned SSL certificate matches the current website certificate.
+ if (!currentWebsiteIssuedToCName.equals(pinnedDomainSslIssuedToCNameString) || !currentWebsiteIssuedToOName.equals(pinnedDomainSslIssuedToONameString) || !currentWebsiteIssuedToUName.equals(pinnedDomainSslIssuedToUNameString) ||
+ !currentWebsiteIssuedByCName.equals(pinnedDomainSslIssuedByCNameString) || !currentWebsiteIssuedByOName.equals(pinnedDomainSslIssuedByONameString) || !currentWebsiteIssuedByUName.equals(pinnedDomainSslIssuedByUNameString) ||
+ !currentWebsiteSslStartDateString.equals(pinnedDomainSslStartDateString) || !currentWebsiteSslEndDateString.equals(pinnedDomainSslEndDateString)) { // The pinned SSL certificate doesn't match the current domain certificate.
+ //Display the pinned SSL certificate mismatch `AlertDialog`.
+ AppCompatDialogFragment pinnedSslCertificateMismatchDialogFragment = new PinnedSslCertificateMismatchDialog();
+ pinnedSslCertificateMismatchDialogFragment.show(getSupportFragmentManager(), getResources().getString(R.string.ssl_certificate_mismatch));
+ }
+ }
}
}
// Handle SSL Certificate errors.
@Override
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
- // Store `handler` so it can be accesses from `onSslErrorCancel()` and `onSslErrorProceed()`.
- sslErrorHandler = handler;
-
- // Display the SSL error `AlertDialog`.
- AppCompatDialogFragment sslCertificateErrorDialogFragment = SslCertificateErrorDialog.displayDialog(error);
- sslCertificateErrorDialogFragment.show(getSupportFragmentManager(), getResources().getString(R.string.ssl_certificate_error));
+ // Get the current website SSL certificate.
+ SslCertificate currentWebsiteSslCertificate = error.getCertificate();
+
+ // Extract the individual pieces of information from the current website SSL certificate.
+ String currentWebsiteIssuedToCName = currentWebsiteSslCertificate.getIssuedTo().getCName();
+ String currentWebsiteIssuedToOName = currentWebsiteSslCertificate.getIssuedTo().getOName();
+ String currentWebsiteIssuedToUName = currentWebsiteSslCertificate.getIssuedTo().getUName();
+ String currentWebsiteIssuedByCName = currentWebsiteSslCertificate.getIssuedBy().getCName();
+ String currentWebsiteIssuedByOName = currentWebsiteSslCertificate.getIssuedBy().getOName();
+ String currentWebsiteIssuedByUName = currentWebsiteSslCertificate.getIssuedBy().getUName();
+ Date currentWebsiteSslStartDate = currentWebsiteSslCertificate.getValidNotBeforeDate();
+ Date currentWebsiteSslEndDate = currentWebsiteSslCertificate.getValidNotAfterDate();
+
+ // Proceed to the website if the current SSL website certificate matches the pinned domain certificate.
+ if (pinnedDomainSslCertificate &&
+ currentWebsiteIssuedToCName.equals(pinnedDomainSslIssuedToCNameString) && currentWebsiteIssuedToOName.equals(pinnedDomainSslIssuedToONameString) && currentWebsiteIssuedToUName.equals(pinnedDomainSslIssuedToUNameString) &&
+ currentWebsiteIssuedByCName.equals(pinnedDomainSslIssuedByCNameString) && currentWebsiteIssuedByOName.equals(pinnedDomainSslIssuedByONameString) && currentWebsiteIssuedByUName.equals(pinnedDomainSslIssuedByUNameString) &&
+ currentWebsiteSslStartDate.equals(pinnedDomainSslStartDate) && currentWebsiteSslEndDate.equals(pinnedDomainSslEndDate)) { // An SSL certificate is pinned and matches the current domain certificate.
+ // Proceed to the website without displaying an error.
+ handler.proceed();
+ } else { // Either there isn't a pinned SSL certificate or it doesn't match the current website certificate.
+ // Store `handler` so it can be accesses from `onSslErrorCancel()` and `onSslErrorProceed()`.
+ sslErrorHandler = handler;
+
+ // Display the SSL error `AlertDialog`.
+ AppCompatDialogFragment sslCertificateErrorDialogFragment = SslCertificateErrorDialog.displayDialog(error);
+ sslCertificateErrorDialogFragment.show(getSupportFragmentManager(), getResources().getString(R.string.ssl_certificate_error));
+ }
}
});
findOnPageLinearLayout.setVisibility(View.VISIBLE);
// Display the keyboard. We have to wait 200 ms before running the command to work around a bug in Android. http://stackoverflow.com/questions/5520085/android-show-softkeyboard-with-showsoftinput-is-not-working
- findOnPageEditText.postDelayed(new Runnable()
- {
+ findOnPageEditText.postDelayed(new Runnable() {
@Override
public void run()
{
sslErrorHandler.proceed();
}
+ @Override
+ public void onSslMismatchBack() {
+ if (mainWebView.canGoBack()) { // There is a back page in the history.
+ // Set `navigatingHistory` so that the domain settings are applied when the new URL is loaded.
+ navigatingHistory = true;
+
+ // Go back.
+ mainWebView.goBack();
+ } else { // There are no pages to go back to.
+ // Load a blank page
+ loadUrl("");
+ }
+ }
+
+ @Override
+ public void onSslMismatchProceed() {
+ // Do not check the pinned SSL certificate for this domain again until the domain changes.
+ ignorePinnedSslCertificate = true;
+ }
+
@Override
public void onUrlHistoryEntrySelected(int moveBackOrForwardSteps) {
// Set `navigatingHistory` so that the domain settings are applied when the new URL is loaded.
// Set the new `hostname` as the `currentDomainName`.
currentDomainName = hostName;
+ // Reset `ignorePinnedSslCertificate`.
+ ignorePinnedSslCertificate = false;
+
// Reset `favoriteIconBitmap` and display it in the `appbar`.
favoriteIconBitmap = favoriteIconDefaultBitmap;
favoriteIconImageView.setImageBitmap(Bitmap.createScaledBitmap(favoriteIconBitmap, 64, 64, true));
currentHostDomainSettingsCursor.moveToFirst();
// Get the settings from the cursor.
+ domainSettingsDatabaseId = (currentHostDomainSettingsCursor.getInt(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper._ID)));
javaScriptEnabled = (currentHostDomainSettingsCursor.getInt(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_JAVASCRIPT)) == 1);
firstPartyCookiesEnabled = (currentHostDomainSettingsCursor.getInt(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FIRST_PARTY_COOKIES)) == 1);
thirdPartyCookiesEnabled = (currentHostDomainSettingsCursor.getInt(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_THIRD_PARTY_COOKIES)) == 1);
String userAgentString = currentHostDomainSettingsCursor.getString(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.USER_AGENT));
int fontSize = currentHostDomainSettingsCursor.getInt(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.FONT_SIZE));
displayWebpageImagesInt = currentHostDomainSettingsCursor.getInt(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.DISPLAY_IMAGES));
+ pinnedDomainSslCertificate = (currentHostDomainSettingsCursor.getInt(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.PINNED_SSL_CERTIFICATE)) == 1);
+ pinnedDomainSslIssuedToCNameString = currentHostDomainSettingsCursor.getString(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_TO_COMMON_NAME));
+ pinnedDomainSslIssuedToONameString = currentHostDomainSettingsCursor.getString(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_TO_ORGANIZATION));
+ pinnedDomainSslIssuedToUNameString = currentHostDomainSettingsCursor.getString(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_TO_ORGANIZATIONAL_UNIT));
+ pinnedDomainSslIssuedByCNameString = currentHostDomainSettingsCursor.getString(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_BY_COMMON_NAME));
+ pinnedDomainSslIssuedByONameString = currentHostDomainSettingsCursor.getString(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_BY_ORGANIZATION));
+ pinnedDomainSslIssuedByUNameString = currentHostDomainSettingsCursor.getString(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_BY_ORGANIZATIONAL_UNIT));
+
+ // Set the pinned SSL certificate start date to `null` if the saved date `long` is 0.
+ if (currentHostDomainSettingsCursor.getLong(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.SSL_START_DATE)) == 0) {
+ pinnedDomainSslStartDate = null;
+ } else {
+ pinnedDomainSslStartDate = new Date(currentHostDomainSettingsCursor.getLong(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.SSL_START_DATE)));
+ }
+
+ // Set the pinned SSL certificate end date to `null` if the saved date `long` is 0.
+ if (currentHostDomainSettingsCursor.getLong(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.SSL_END_DATE)) == 0) {
+ pinnedDomainSslEndDate = null;
+ } else {
+ pinnedDomainSslEndDate = new Date(currentHostDomainSettingsCursor.getLong(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.SSL_END_DATE)));
+ }
// Close `currentHostDomainSettingsCursor`.
currentHostDomainSettingsCursor.close();
mainWebView.getSettings().setSaveFormData(saveFormDataEnabled);
mainWebView.getSettings().setTextZoom(Integer.valueOf(defaultFontSizeString));
+ // Reset the pinned SSL certificate information.
+ domainSettingsDatabaseId = -1;
+ pinnedDomainSslCertificate = false;
+ pinnedDomainSslIssuedToCNameString = "";
+ pinnedDomainSslIssuedToONameString = "";
+ pinnedDomainSslIssuedToUNameString = "";
+ pinnedDomainSslIssuedByCNameString = "";
+ pinnedDomainSslIssuedByONameString = "";
+ pinnedDomainSslIssuedByUNameString = "";
+ pinnedDomainSslStartDate = null;
+ pinnedDomainSslEndDate = null;
+
// Set third-party cookies status if API >= 21.
if (Build.VERSION.SDK_INT >= 21) {
cookieManager.setAcceptThirdPartyCookies(mainWebView, thirdPartyCookiesEnabled);
--- /dev/null
+package com.stoutner.privacybrowser.definitions;
+
+/*
+ * Copyright © 2017 Soren Stoutner <soren@stoutner.com>.
+ *
+ * This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
+ *
+ * Privacy Browser is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Privacy Browser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Privacy Browser. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+import android.content.Context;
+import android.support.v4.view.ViewPager;
+import android.util.AttributeSet;
+import android.view.View;
+
+public class WrapVerticalContentViewPager extends ViewPager {
+ // Setup the default constructors.
+ public WrapVerticalContentViewPager(Context context) {
+ super(context);
+ }
+
+ public WrapVerticalContentViewPager(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ // Perform an initial `super.onMeasure`, which populates `getChildCount`.
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+
+ // Initialize `maximumHeight`.
+ int maximumHeight = 0;
+
+ // Find the maximum height of each of the child views.
+ for (int i = 0; i < getChildCount(); i++) {
+ View childView = getChildAt(i);
+
+ // Measure the child view height with no constraints.
+ childView.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
+
+ // Store the child's height if it is larger than `maximumHeight`.
+ if (childView.getMeasuredHeight() > maximumHeight) {
+ maximumHeight = childView.getMeasuredHeight();
+ }
+ }
+
+ // Perform a final `super.onMeasure` to set the `maximumHeight`.
+ super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(maximumHeight, MeasureSpec.EXACTLY));
+ }
+}
\ No newline at end of file
// Set the view. The parent view is `null` because it will be assigned by `AlertDialog`.
dialogBuilder.setView(layoutInflater.inflate(R.layout.create_home_screen_shortcut_dialog, null));
- // Set an `onClick` listener on the negative button.
- dialogBuilder.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- // Do nothing if `Cancel` is clicked.
- }
- });
+ // Setup the negative button. Using `null` closes the dialog without doing anything else.
+ dialogBuilder.setNegativeButton(R.string.cancel, null);
// Set an `onClick` listener on the positive button.
dialogBuilder.setPositiveButton(R.string.create, new DialogInterface.OnClickListener() {
--- /dev/null
+/*
+ * Copyright © 2017 Soren Stoutner <soren@stoutner.com>.
+ *
+ * This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
+ *
+ * Privacy Browser is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Privacy Browser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Privacy Browser. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package com.stoutner.privacybrowser.dialogs;
+
+import android.annotation.SuppressLint;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.net.http.SslCertificate;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.design.widget.TabLayout;
+import android.support.v4.view.PagerAdapter;
+// We have to use `AppCompatDialogFragment` instead of `DialogFragment` or an error is produced on API <=22.
+import android.support.v7.app.AppCompatDialogFragment;
+import android.text.SpannableStringBuilder;
+import android.text.Spanned;
+import android.text.style.ForegroundColorSpan;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import com.stoutner.privacybrowser.R;
+import com.stoutner.privacybrowser.activities.MainWebViewActivity;
+import com.stoutner.privacybrowser.definitions.WrapVerticalContentViewPager;
+import com.stoutner.privacybrowser.helpers.DomainsDatabaseHelper;
+
+import java.text.DateFormat;
+import java.util.Date;
+
+// `@SuppressLing("InflateParams")` removes the warning about using `null` as the parent view group when inflating the `AlertDialog`.
+@SuppressLint("InflateParams")
+public class PinnedSslCertificateMismatchDialog extends AppCompatDialogFragment {
+ // `layoutInflater` is used in `onCreateDialog()` and `pagerAdapter`.
+ private LayoutInflater layoutInflater;
+
+ // The current website SSL certificate variables are used in `onCreateDialog()` and `pagerAdapter()`.
+ private String currentSslIssuedToCNameString;
+ private String currentSslIssuedToONameString;
+ private String currentSslIssuedToUNameString;
+ private String currentSslIssuedByCNameString;
+ private String currentSslIssuedByONameString;
+ private String currentSslIssuedByUNameString;
+ private Date currentSslStartDate;
+ private Date currentSslEndDate;
+
+ // The public interface is used to send information back to the parent activity.
+ public interface PinnedSslCertificateMismatchListener {
+ void onSslMismatchBack();
+
+ void onSslMismatchProceed();
+ }
+
+ // `sslCertificateErrorListener` is used in `onAttach` and `onCreateDialog`.
+ private PinnedSslCertificateMismatchDialog.PinnedSslCertificateMismatchListener pinnedSslCertificateMismatchListener;
+
+ // Check to make sure that the parent activity implements the listener.
+ public void onAttach(Context context) {
+ super.onAttach(context);
+
+ try {
+ pinnedSslCertificateMismatchListener = (PinnedSslCertificateMismatchDialog.PinnedSslCertificateMismatchListener) context;
+ } catch(ClassCastException exception) {
+ throw new ClassCastException(context.toString() + " must implement PinnedSslCertificateMismatchListener");
+ }
+ }
+
+ @NonNull
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ // Get the activity's layout inflater.
+ layoutInflater = getActivity().getLayoutInflater();
+
+ // Use `AlertDialog.Builder` to create the `AlertDialog`.
+ AlertDialog.Builder dialogBuilder;
+
+ // Set the style according to the theme.
+ if (MainWebViewActivity.darkTheme) {
+ // Set the dialog theme.
+ dialogBuilder = new AlertDialog.Builder(getActivity(), R.style.PrivacyBrowserAlertDialogDark);
+
+ // Set the icon.
+ dialogBuilder.setIcon(R.drawable.ssl_certificate_enabled_dark);
+ } else {
+ // Set the dialog theme.
+ dialogBuilder = new AlertDialog.Builder(getActivity(), R.style.PrivacyBrowserAlertDialogLight);
+
+ // Set the icon.
+ dialogBuilder.setIcon(R.drawable.ssl_certificate_enabled_light);
+ }
+
+ // Setup the neutral button.
+ dialogBuilder.setNeutralButton(R.string.update_ssl, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ // Initialize the `long` date variables. If the date is `null`, a long value of `0` will be stored in the Domains database entry.
+ long currentSslStartDateLong = 0;
+ long currentSslEndDateLong = 0;
+
+ // Convert the `Dates` into `longs`.
+ if (currentSslStartDate != null) {
+ currentSslStartDateLong = currentSslStartDate.getTime();
+ }
+
+ if (currentSslEndDate != null) {
+ currentSslEndDateLong = currentSslEndDate.getTime();
+ }
+
+ // Initialize the database handler. The two `nulls` do not specify the database name or a `CursorFactory`. The `0` specifies the database version, but that is ignored and set instead using a constant in `DomainsDatabaseHelper`.
+ DomainsDatabaseHelper domainsDatabaseHelper = new DomainsDatabaseHelper(getContext(), null, null, 0);
+
+ // Update the pinned SSL certificate for this domain.
+ domainsDatabaseHelper.updateCertificate(MainWebViewActivity.domainSettingsDatabaseId, currentSslIssuedToCNameString, currentSslIssuedToONameString, currentSslIssuedToUNameString, currentSslIssuedByCNameString, currentSslIssuedByONameString,
+ currentSslIssuedByUNameString, currentSslStartDateLong, currentSslEndDateLong);
+
+ // Update the pinned SSL certificate global variables to match the information that is now in the database.
+ MainWebViewActivity.pinnedDomainSslIssuedToCNameString = currentSslIssuedToCNameString;
+ MainWebViewActivity.pinnedDomainSslIssuedToONameString = currentSslIssuedToONameString;
+ MainWebViewActivity.pinnedDomainSslIssuedToUNameString = currentSslIssuedToUNameString;
+ MainWebViewActivity.pinnedDomainSslIssuedByCNameString = currentSslIssuedByCNameString;
+ MainWebViewActivity.pinnedDomainSslIssuedByONameString = currentSslIssuedByONameString;
+ MainWebViewActivity.pinnedDomainSslIssuedByUNameString = currentSslIssuedByUNameString;
+ MainWebViewActivity.pinnedDomainSslStartDate = currentSslStartDate;
+ MainWebViewActivity.pinnedDomainSslEndDate = currentSslEndDate;
+ }
+ });
+
+ // Setup the negative button.
+ dialogBuilder.setNegativeButton(R.string.back, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ // Call the `onSslMismatchBack` public interface to send the `WebView` back one page.
+ pinnedSslCertificateMismatchListener.onSslMismatchBack();
+ }
+ });
+
+ // Setup the positive button.
+ dialogBuilder.setPositiveButton(R.string.proceed, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ // Call the `onSslMismatchProceed` public interface.
+ pinnedSslCertificateMismatchListener.onSslMismatchProceed();
+ }
+ });
+
+ // Set the title.
+ dialogBuilder.setTitle(R.string.ssl_certificate_mismatch);
+
+ // Set the layout. The parent view is `null` because it will be assigned by `AlertDialog`.
+ dialogBuilder.setView(layoutInflater.inflate(R.layout.pinned_ssl_certificate_mismatch_linearlayout, null));
+
+ // Create an `AlertDialog` from the `AlertDialog.Builder`
+ final AlertDialog alertDialog = dialogBuilder.create();
+
+ // Show the `AlertDialog` so the items in the layout can be modified.
+ alertDialog.show();
+
+ // Setup `wrapVerticalContentViewPager`.
+ WrapVerticalContentViewPager wrapVerticalContentViewPager = (WrapVerticalContentViewPager) alertDialog.findViewById(R.id.pinned_ssl_certificate_mismatch_viewpager);
+ wrapVerticalContentViewPager.setAdapter(new pagerAdapter());
+
+ // Setup the `TabLayout` and connect it to the `WrapVerticalContentViewPager`.
+ TabLayout tabLayout = (TabLayout) alertDialog.findViewById(R.id.pinned_ssl_certificate_mismatch_tablayout);
+ tabLayout.setupWithViewPager(wrapVerticalContentViewPager);
+
+ // `onCreateDialog` requires the return of an `AlertDialog`.
+ return alertDialog;
+ }
+
+ private class pagerAdapter extends PagerAdapter {
+ @Override
+ public boolean isViewFromObject(View view, Object object) {
+ // Check to see if the `View` and the `Object` are the same.
+ return (view == object);
+ }
+
+ @Override
+ public int getCount() {
+ // There are two tabs.
+ return 2;
+ }
+
+ @Override
+ public CharSequence getPageTitle(int position) {
+ // Return the current tab title.
+ if (position == 0) { // The current SSL certificate tab.
+ return getString(R.string.current_ssl);
+ } else { // The pinned SSL certificate tab.
+ return getString(R.string.pinned_ssl);
+ }
+ }
+
+ @Override
+ public Object instantiateItem(ViewGroup container, int position) {
+ // Inflate the `ScrollView` for this tab.
+ ViewGroup tabViewGroup = (ViewGroup) layoutInflater.inflate(R.layout.pinned_ssl_certificate_mismatch_scrollview, container, false);
+
+ // Get handles for the `TextViews`.
+ TextView issuedToCNameTextView = (TextView) tabViewGroup.findViewById(R.id.issued_to_cname);
+ TextView issuedToONameTextView = (TextView) tabViewGroup.findViewById(R.id.issued_to_oname);
+ TextView issuedToUNameTextView = (TextView) tabViewGroup.findViewById(R.id.issued_to_uname);
+ TextView issuedByCNameTextView = (TextView) tabViewGroup.findViewById(R.id.issued_by_cname);
+ TextView issuedByONameTextView = (TextView) tabViewGroup.findViewById(R.id.issued_by_oname);
+ TextView issuedByUNameTextView = (TextView) tabViewGroup.findViewById(R.id.issued_by_uname);
+ TextView startDateTextView = (TextView) tabViewGroup.findViewById(R.id.start_date);
+ TextView endDateTextView = (TextView) tabViewGroup.findViewById(R.id.end_date);
+
+ // Setup the labels.
+ String cNameLabel = getString(R.string.common_name) + " ";
+ String oNameLabel = getString(R.string.organization) + " ";
+ String uNameLabel = getString(R.string.organizational_unit) + " ";
+ String startDateLabel = getString(R.string.start_date) + " ";
+ String endDateLabel = getString(R.string.end_date) + " ";
+
+ // Get the current website SSL certificate.
+ SslCertificate sslCertificate = MainWebViewActivity.sslCertificate;
+
+ // Extract the individual pieces of information from the current website SSL certificate if it is not null.
+ if (sslCertificate != null) {
+ currentSslIssuedToCNameString = sslCertificate.getIssuedTo().getCName();
+ currentSslIssuedToONameString = sslCertificate.getIssuedTo().getOName();
+ currentSslIssuedToUNameString = sslCertificate.getIssuedTo().getUName();
+ currentSslIssuedByCNameString = sslCertificate.getIssuedBy().getCName();
+ currentSslIssuedByONameString = sslCertificate.getIssuedBy().getOName();
+ currentSslIssuedByUNameString = sslCertificate.getIssuedBy().getUName();
+ currentSslStartDate = sslCertificate.getValidNotBeforeDate();
+ currentSslEndDate = sslCertificate.getValidNotAfterDate();
+ } else {
+ // Initialize the current website SSL certificate variables with blank information.
+ currentSslIssuedToCNameString = "";
+ currentSslIssuedToONameString = "";
+ currentSslIssuedToUNameString = "";
+ currentSslIssuedByCNameString = "";
+ currentSslIssuedByONameString = "";
+ currentSslIssuedByUNameString = "";
+ }
+
+ // Initialize the `SpannableStringBuilders`.
+ SpannableStringBuilder issuedToCNameStringBuilder;
+ SpannableStringBuilder issuedToONameStringBuilder;
+ SpannableStringBuilder issuedToUNameStringBuilder;
+ SpannableStringBuilder issuedByCNameStringBuilder;
+ SpannableStringBuilder issuedByONameStringBuilder;
+ SpannableStringBuilder issuedByUNameStringBuilder;
+ SpannableStringBuilder startDateStringBuilder;
+ SpannableStringBuilder endDateStringBuilder;
+
+ // Setup the `SpannableStringBuilders` for each tab.
+ if (position == 0) { // Setup the current SSL certificate tab.
+ issuedToCNameStringBuilder = new SpannableStringBuilder(cNameLabel + currentSslIssuedToCNameString);
+ issuedToONameStringBuilder = new SpannableStringBuilder(oNameLabel + currentSslIssuedToONameString);
+ issuedToUNameStringBuilder = new SpannableStringBuilder(uNameLabel + currentSslIssuedToUNameString);
+ issuedByCNameStringBuilder = new SpannableStringBuilder(cNameLabel + currentSslIssuedByCNameString);
+ issuedByONameStringBuilder = new SpannableStringBuilder(oNameLabel + currentSslIssuedByONameString);
+ issuedByUNameStringBuilder = new SpannableStringBuilder(uNameLabel + currentSslIssuedByUNameString);
+
+ // Set the dates if they aren't `null`.
+ if (currentSslStartDate == null) {
+ startDateStringBuilder = new SpannableStringBuilder(startDateLabel);
+ } else {
+ startDateStringBuilder = new SpannableStringBuilder(startDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(currentSslStartDate));
+ }
+
+ if (currentSslEndDate == null) {
+ endDateStringBuilder = new SpannableStringBuilder(endDateLabel);
+ } else {
+ endDateStringBuilder = new SpannableStringBuilder(endDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(currentSslEndDate));
+ }
+ } else { // Setup the pinned SSL certificate tab.
+ issuedToCNameStringBuilder = new SpannableStringBuilder(cNameLabel + MainWebViewActivity.pinnedDomainSslIssuedToCNameString);
+ issuedToONameStringBuilder = new SpannableStringBuilder(oNameLabel + MainWebViewActivity.pinnedDomainSslIssuedToONameString);
+ issuedToUNameStringBuilder = new SpannableStringBuilder(uNameLabel + MainWebViewActivity.pinnedDomainSslIssuedToUNameString);
+ issuedByCNameStringBuilder = new SpannableStringBuilder(cNameLabel + MainWebViewActivity.pinnedDomainSslIssuedByCNameString);
+ issuedByONameStringBuilder = new SpannableStringBuilder(oNameLabel + MainWebViewActivity.pinnedDomainSslIssuedByONameString);
+ issuedByUNameStringBuilder = new SpannableStringBuilder(uNameLabel + MainWebViewActivity.pinnedDomainSslIssuedByUNameString);
+
+ // Set the dates if they aren't `null`.
+ if (MainWebViewActivity.pinnedDomainSslStartDate == null) {
+ startDateStringBuilder = new SpannableStringBuilder(startDateLabel);
+ } else {
+ startDateStringBuilder = new SpannableStringBuilder(startDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(MainWebViewActivity.pinnedDomainSslStartDate));
+ }
+
+ if (MainWebViewActivity.pinnedDomainSslEndDate == null) {
+ endDateStringBuilder = new SpannableStringBuilder(endDateLabel);
+ } else {
+ endDateStringBuilder = new SpannableStringBuilder(endDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(MainWebViewActivity.pinnedDomainSslEndDate));
+ }
+ }
+
+ // Create a red `ForegroundColorSpan`. We have to use the deprecated `getColor` until API >= 23.
+ @SuppressWarnings("deprecation") ForegroundColorSpan redColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.red_a700));
+
+ // Create a blue `ForegroundColorSpan`.
+ ForegroundColorSpan blueColorSpan;
+
+ // Set `blueColorSpan` according to the theme. We have to use the deprecated `getColor()` until API >= 23.
+ if (MainWebViewActivity.darkTheme) {
+ //noinspection deprecation
+ blueColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.blue_400));
+ } else {
+ //noinspection deprecation
+ blueColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.blue_700));
+ }
+
+ // Configure the spans to display conflicting information in red. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
+ if (currentSslIssuedToCNameString.equals(MainWebViewActivity.pinnedDomainSslIssuedToCNameString)) {
+ issuedToCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), issuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+ } else {
+ issuedToCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), issuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+ }
+
+ if (currentSslIssuedToONameString.equals(MainWebViewActivity.pinnedDomainSslIssuedToONameString)) {
+ issuedToONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), issuedToONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+ } else {
+ issuedToONameStringBuilder.setSpan(redColorSpan, oNameLabel.length(), issuedToONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+ }
+
+ if (currentSslIssuedToUNameString.equals(MainWebViewActivity.pinnedDomainSslIssuedToUNameString)) {
+ issuedToUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), issuedToUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+ } else {
+ issuedToUNameStringBuilder.setSpan(redColorSpan, uNameLabel.length(), issuedToUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+ }
+
+ if (currentSslIssuedByCNameString.equals(MainWebViewActivity.pinnedDomainSslIssuedByCNameString)) {
+ issuedByCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), issuedByCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+ } else {
+ issuedByCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), issuedByCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+ }
+
+ if (currentSslIssuedByONameString.equals(MainWebViewActivity.pinnedDomainSslIssuedByONameString)) {
+ issuedByONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), issuedByONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+ } else {
+ issuedByONameStringBuilder.setSpan(redColorSpan, oNameLabel.length(), issuedByONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+ }
+
+ if (currentSslIssuedByUNameString.equals(MainWebViewActivity.pinnedDomainSslIssuedByUNameString)) {
+ issuedByUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), issuedByUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+ } else {
+ issuedByUNameStringBuilder.setSpan(redColorSpan, uNameLabel.length(), issuedByUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+ }
+
+ if ((currentSslStartDate != null) && (MainWebViewActivity.pinnedDomainSslStartDate != null) && currentSslStartDate.equals(MainWebViewActivity.pinnedDomainSslStartDate)) {
+ startDateStringBuilder.setSpan(blueColorSpan, startDateLabel.length(), startDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+ } else {
+ startDateStringBuilder.setSpan(redColorSpan, startDateLabel.length(), startDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+ }
+
+ if ((currentSslEndDate != null) && (MainWebViewActivity.pinnedDomainSslEndDate != null) && currentSslEndDate.equals(MainWebViewActivity.pinnedDomainSslEndDate)) {
+ endDateStringBuilder.setSpan(blueColorSpan, endDateLabel.length(), endDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+ } else {
+ endDateStringBuilder.setSpan(redColorSpan, endDateLabel.length(), endDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+ }
+
+ // Display the strings.
+ issuedToCNameTextView.setText(issuedToCNameStringBuilder);
+ issuedToONameTextView.setText(issuedToONameStringBuilder);
+ issuedToUNameTextView.setText(issuedToUNameStringBuilder);
+ issuedByCNameTextView.setText(issuedByCNameStringBuilder);
+ issuedByONameTextView.setText(issuedByONameStringBuilder);
+ issuedByUNameTextView.setText(issuedByUNameStringBuilder);
+ startDateTextView.setText(startDateStringBuilder);
+ endDateTextView.setText(endDateStringBuilder);
+
+ // Display the tab.
+ container.addView(tabViewGroup);
+
+ // Make it so.
+ return tabViewGroup;
+ }
+ }
+}
// Use `AlertDialog.Builder` to create the `AlertDialog`.
AlertDialog.Builder dialogBuilder;
- // Set the style according to the theme.
+ // Set the style and icon according to the theme.
if (MainWebViewActivity.darkTheme) {
+ // Set the style.
dialogBuilder = new AlertDialog.Builder(getActivity(), R.style.PrivacyBrowserAlertDialogDark);
+
+ // Set the icon.
+ dialogBuilder.setIcon(R.drawable.ssl_certificate_enabled_dark);
} else {
+ // Set the style.
dialogBuilder = new AlertDialog.Builder(getActivity(), R.style.PrivacyBrowserAlertDialogLight);
+
+ // Set the icon.
+ dialogBuilder.setIcon(R.drawable.ssl_certificate_enabled_light);
}
// Set the title.
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.SharedPreferences;
+import android.content.res.Resources;
import android.database.Cursor;
+import android.net.http.SslCertificate;
import android.os.Build;
import android.os.Bundle;
// We have to use `android.support.v4.app.Fragment` until minimum API >= 23. Otherwise we cannot call `getContext()`.
import android.preference.PreferenceManager;
import android.support.v4.app.Fragment;
+import android.text.Editable;
+import android.text.SpannableStringBuilder;
+import android.text.Spanned;
+import android.text.TextWatcher;
+import android.text.style.ForegroundColorSpan;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
+import android.widget.RadioButton;
import android.widget.Spinner;
import android.widget.Switch;
import android.widget.TextView;
import com.stoutner.privacybrowser.activities.MainWebViewActivity;
import com.stoutner.privacybrowser.helpers.DomainsDatabaseHelper;
+import java.text.DateFormat;
+import java.util.Calendar;
+import java.util.Date;
+
public class DomainSettingsFragment extends Fragment {
// `DATABASE_ID` is used by activities calling this fragment.
public static final String DATABASE_ID = "database_id";
- // `databaseId` is public statis so it can be accessed from `DomainsActivity`. It is also used in `onCreate()` and `onCreateView()`.
+ // `databaseId` is public static so it can be accessed from `DomainsActivity`. It is also used in `onCreate()` and `onCreateView()`.
public static int databaseId;
@Override
// Inflate `domain_settings_fragment`. `false` does not attach it to the root `container`.
View domainSettingsView = inflater.inflate(R.layout.domain_settings_fragment, container, false);
- // Get a handle for the `Context`.
+ // Get a handle for the `Context` and the `Resources`.
Context context = getContext();
+ final Resources resources = getResources();
+
+ // Get a handle for the shared preference.
+ SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
+
+ // Store the default user agent string values.
+ final String defaultUserAgentString = sharedPreferences.getString("user_agent", "PrivacyBrowser/1.0");
+ final String defaultCustomUserAgentString = sharedPreferences.getString("custom_user_agent", "PrivacyBrowser/1.0");
+ String defaultFontSizeString = sharedPreferences.getString("default_font_size", "100");
+ boolean defaultDisplayWebpageImagesBoolean = sharedPreferences.getBoolean("display_website_images", true);
// Get handles for the views in the fragment.
- EditText domainNameEditText = (EditText) domainSettingsView.findViewById(R.id.domain_settings_name_edittext);
+ final EditText domainNameEditText = (EditText) domainSettingsView.findViewById(R.id.domain_settings_name_edittext);
Switch javaScriptEnabledSwitch = (Switch) domainSettingsView.findViewById(R.id.domain_settings_javascript_switch);
final ImageView javaScriptImageView = (ImageView) domainSettingsView.findViewById(R.id.domain_settings_javascript_imageview);
Switch firstPartyCookiesEnabledSwitch = (Switch) domainSettingsView.findViewById(R.id.domain_settings_first_party_cookies_switch);
final TextView userAgentTextView = (TextView) domainSettingsView.findViewById(R.id.domain_settings_user_agent_textview);
final EditText customUserAgentEditText = (EditText) domainSettingsView.findViewById(R.id.domain_settings_custom_user_agent_edittext);
Spinner fontSizeSpinner = (Spinner) domainSettingsView.findViewById(R.id.domain_settings_font_size_spinner);
+ final TextView fontSizeTextView = (TextView) domainSettingsView.findViewById(R.id.domain_settings_font_size_textview);
final ImageView displayWebpageImagesImageView = (ImageView) domainSettingsView.findViewById(R.id.domain_settings_display_webpage_images_imageview);
Spinner displayWebpageImagesSpinner = (Spinner) domainSettingsView.findViewById(R.id.domain_settings_display_webpage_images_spinner);
+ final TextView displayImagesTextView = (TextView) domainSettingsView.findViewById(R.id.domain_settings_display_webpage_images_textview);
+ final ImageView pinnedSslCertificateImageView = (ImageView) domainSettingsView.findViewById(R.id.domain_settings_pinned_ssl_certificate_imageview);
+ Switch pinnedSslCertificateSwitch = (Switch) domainSettingsView.findViewById(R.id.domain_settings_pinned_ssl_certificate_switch);
+ final LinearLayout savedSslCertificateLinearLayout = (LinearLayout) domainSettingsView.findViewById(R.id.saved_ssl_certificate_linearlayout);
+ final RadioButton savedSslCertificateRadioButton = (RadioButton) domainSettingsView.findViewById(R.id.saved_ssl_certificate_radiobutton);
+ final TextView savedSslCertificateIssuedToCNameTextView = (TextView) domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_to_cname);
+ TextView savedSslCertificateIssuedToONameTextView = (TextView) domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_to_oname);
+ TextView savedSslCertificateIssuedToUNameTextView = (TextView) domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_to_uname);
+ TextView savedSslCertificateIssuedByCNameTextView = (TextView) domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_by_cname);
+ TextView savedSslCertificateIssuedByONameTextView = (TextView) domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_by_oname);
+ TextView savedSslCertificateIssuedByUNameTextView = (TextView) domainSettingsView.findViewById(R.id.saved_ssl_certificate_issued_by_uname);
+ TextView savedSslCertificateStartDateTextView = (TextView) domainSettingsView.findViewById(R.id.saved_ssl_certificate_start_date);
+ TextView savedSslCertificateEndDateTextView = (TextView) domainSettingsView.findViewById(R.id.saved_ssl_certificate_end_date);
+ final LinearLayout currentWebsiteCertificateLinearLayout = (LinearLayout) domainSettingsView.findViewById(R.id.current_website_certificate_linearlayout);
+ final RadioButton currentWebsiteCertificateRadioButton = (RadioButton) domainSettingsView.findViewById(R.id.current_website_certificate_radiobutton);
+ final TextView currentWebsiteCertificateIssuedToCNameTextView = (TextView) domainSettingsView.findViewById(R.id.current_website_certificate_issued_to_cname);
+ TextView currentWebsiteCertificateIssuedToONameTextView = (TextView) domainSettingsView.findViewById(R.id.current_website_certificate_issued_to_oname);
+ TextView currentWebsiteCertificateIssuedToUNameTextView = (TextView) domainSettingsView.findViewById(R.id.current_website_certificate_issued_to_uname);
+ TextView currentWebsiteCertificateIssuedByCNameTextView = (TextView) domainSettingsView.findViewById(R.id.current_website_certificate_issued_by_cname);
+ TextView currentWebsiteCertificateIssuedByONameTextView = (TextView) domainSettingsView.findViewById(R.id.current_website_certificate_issued_by_oname);
+ TextView currentWebsiteCertificateIssuedByUNameTextView = (TextView) domainSettingsView.findViewById(R.id.current_website_certificate_issued_by_uname);
+ TextView currentWebsiteCertificateStartDateTextView = (TextView) domainSettingsView.findViewById(R.id.current_website_certificate_start_date);
+ TextView currentWebsiteCertificateEndDateTextView = (TextView) domainSettingsView.findViewById(R.id.current_website_certificate_end_date);
+ final TextView noCurrentWebsiteCertificateTextView = (TextView) domainSettingsView.findViewById(R.id.no_current_website_certificate);
+
+ // Setup the SSL certificate labels.
+ final String cNameLabel = getString(R.string.common_name) + " ";
+ String oNameLabel = getString(R.string.organization) + " ";
+ String uNameLabel = getString(R.string.organizational_unit) + " ";
+ String startDateLabel = getString(R.string.start_date) + " ";
+ String endDateLabel = getString(R.string.end_date) + " ";
+
+ // Get the current website SSL certificate
+ final SslCertificate currentWebsiteSslCertificate = MainWebViewActivity.sslCertificate;
// Initialize the database handler. The two `nulls` do not specify the database name or a `CursorFactory`. The `0` specifies the database version, but that is ignored and set instead using a constant in `DomainsDatabaseHelper`.
DomainsDatabaseHelper domainsDatabaseHelper = new DomainsDatabaseHelper(context, null, null, 0);
final String currentUserAgentString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.USER_AGENT));
int fontSizeInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.FONT_SIZE));
int displayImagesInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.DISPLAY_IMAGES));
+ int pinnedSslCertificateInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.PINNED_SSL_CERTIFICATE));
+ final String savedSslCertificateIssuedToCNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_TO_COMMON_NAME));
+ String savedSslCertificateIssuedToONameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_TO_ORGANIZATION));
+ String savedSslCertificateIssuedToUNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_TO_ORGANIZATIONAL_UNIT));
+ String savedSslCertificateIssuedByCNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_BY_COMMON_NAME));
+ String savedSslCertificateIssuedByONameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_BY_ORGANIZATION));
+ String savedSslCertificateIssuedByUNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_BY_ORGANIZATIONAL_UNIT));
+
+ // Initialize the saved SSL certificate date variables.
+ Date savedSslCertificateStartDate = null;
+ Date savedSslCertificateEndDate = null;
+
+ // Only get the saved SSL certificate dates from the cursor if they are not set to `0`.
+ if (domainCursor.getLong(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_START_DATE)) != 0) {
+ savedSslCertificateStartDate = new Date(domainCursor.getLong(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_START_DATE)));
+ }
+
+ if (domainCursor.getLong(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_END_DATE)) != 0) {
+ savedSslCertificateEndDate = new Date(domainCursor.getLong(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_END_DATE)));
+ }
// Create `ArrayAdapters` for the `Spinners`and their `entry values`.
ArrayAdapter<CharSequence> userAgentArrayAdapter = ArrayAdapter.createFromResource(context, R.array.domain_settings_user_agent_entries, R.layout.spinner_item);
fontSizeSpinner.setAdapter(fontSizeArrayAdapter);
displayWebpageImagesSpinner.setAdapter(displayImagesArrayAdapter);
+ // Create a `SpannableStringBuilder` for each `TextView` that needs multiple colors of text.
+ SpannableStringBuilder savedSslCertificateIssuedToCNameStringBuilder = new SpannableStringBuilder(cNameLabel + savedSslCertificateIssuedToCNameString);
+ SpannableStringBuilder savedSslCertificateIssuedToONameStringBuilder = new SpannableStringBuilder(oNameLabel + savedSslCertificateIssuedToONameString);
+ SpannableStringBuilder savedSslCertificateIssuedToUNameStringBuilder = new SpannableStringBuilder(uNameLabel + savedSslCertificateIssuedToUNameString);
+ SpannableStringBuilder savedSslCertificateIssuedByCNameStringBuilder = new SpannableStringBuilder(cNameLabel + savedSslCertificateIssuedByCNameString);
+ SpannableStringBuilder savedSslCertificateIssuedByONameStringBuilder = new SpannableStringBuilder(oNameLabel + savedSslCertificateIssuedByONameString);
+ SpannableStringBuilder savedSslCertificateIssuedByUNameStringBuilder = new SpannableStringBuilder(uNameLabel + savedSslCertificateIssuedByUNameString);
+
+ // Initialize the `SpannableStringBuilders` for the SSL certificate dates.
+ SpannableStringBuilder savedSslCertificateStartDateStringBuilder;
+ SpannableStringBuilder savedSslCertificateEndDateStringBuilder;
+
+ // Leave the SSL certificate dates empty if they are `null`.
+ if (savedSslCertificateStartDate == null) {
+ savedSslCertificateStartDateStringBuilder = new SpannableStringBuilder(startDateLabel);
+ } else {
+ savedSslCertificateStartDateStringBuilder = new SpannableStringBuilder(startDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(savedSslCertificateStartDate));
+ }
+
+ if (savedSslCertificateEndDate == null) {
+ savedSslCertificateEndDateStringBuilder = new SpannableStringBuilder(endDateLabel);
+ } else {
+ savedSslCertificateEndDateStringBuilder = new SpannableStringBuilder(endDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(savedSslCertificateEndDate));
+ }
+
+ // Create a red `ForegroundColorSpan`. We have to use the deprecated `getColor` until API >= 23.
+ final ForegroundColorSpan redColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.red_a700));
+
+ // Create a blue `ForegroundColorSpan`.
+ final ForegroundColorSpan blueColorSpan;
+
+ // Set `blueColorSpan` according to the theme. We have to use the deprecated `getColor()` until API >= 23.
+ if (MainWebViewActivity.darkTheme) {
+ //noinspection deprecation
+ blueColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.blue_400));
+ } else {
+ //noinspection deprecation
+ blueColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.blue_700));
+ }
+
// Set the domain name from the the database cursor.
domainNameEditText.setText(domainNameString);
+ // Update the certificates' `Common Name` color when the domain name text changes.
+ domainNameEditText.addTextChangedListener(new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+ // Do nothing.
+ }
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ // Do nothing.
+ }
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ // Get the new domain name.
+ String newDomainName = domainNameEditText.getText().toString();
+
+ // Check the saved SSL certificate against the new domain name.
+ boolean savedSslCertificateMatchesNewDomainName = checkDomainNameAgainstCertificate(newDomainName, savedSslCertificateIssuedToCNameString);
+
+ // Create a `SpannableStringBuilder` for the saved certificate `Common Name`.
+ SpannableStringBuilder savedSslCertificateCommonNameStringBuilder = new SpannableStringBuilder(cNameLabel + savedSslCertificateIssuedToCNameString);
+
+ // Format the saved certificate `Common Name` color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
+ if (savedSslCertificateMatchesNewDomainName) {
+ savedSslCertificateCommonNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), savedSslCertificateCommonNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+ } else {
+ savedSslCertificateCommonNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), savedSslCertificateCommonNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+ }
+
+ // Update `savedSslCertificateIssuedToCNameTextView`.
+ savedSslCertificateIssuedToCNameTextView.setText(savedSslCertificateCommonNameStringBuilder);
+
+ // Update the current website certificate if it exists.
+ if (currentWebsiteSslCertificate != null) {
+ // Get the current website certificate `Common Name`.
+ String currentWebsiteCertificateCommonName = currentWebsiteSslCertificate.getIssuedTo().getCName();
+
+ // Check the current website certificate against the new domain name.
+ boolean currentWebsiteCertificateMatchesNewDomainName = checkDomainNameAgainstCertificate(newDomainName, currentWebsiteCertificateCommonName);
+
+ // Create a `SpannableStringBuilder` for the current website certificate `Common Name`.
+ SpannableStringBuilder currentWebsiteCertificateCommonNameStringBuilder = new SpannableStringBuilder(cNameLabel + currentWebsiteCertificateCommonName);
+
+ // Format the current certificate `Common Name` color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
+ if (currentWebsiteCertificateMatchesNewDomainName) {
+ currentWebsiteCertificateCommonNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), currentWebsiteCertificateCommonNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+ } else {
+ currentWebsiteCertificateCommonNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), currentWebsiteCertificateCommonNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+ }
+
+ // Update `currentWebsiteCertificateIssuedToCNameTextView`.
+ currentWebsiteCertificateIssuedToCNameTextView.setText(currentWebsiteCertificateCommonNameStringBuilder);
+ }
+ }
+ });
+
// Set the JavaScript status.
if (javaScriptEnabledInt == 1) { // JavaScript is enabled.
javaScriptEnabledSwitch.setChecked(true);
- javaScriptImageView.setImageDrawable(getResources().getDrawable(R.drawable.javascript_enabled));
+ javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.javascript_enabled));
} else { // JavaScript is disabled.
javaScriptEnabledSwitch.setChecked(false);
- javaScriptImageView.setImageDrawable(getResources().getDrawable(R.drawable.privacy_mode));
+ javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.privacy_mode));
}
// Set the first-party cookies status. Once minimum API >= 21 we can use a selector as the tint mode instead of specifying different icons.
if (firstPartyCookiesEnabledInt == 1) { // First-party cookies are enabled.
firstPartyCookiesEnabledSwitch.setChecked(true);
- firstPartyCookiesImageView.setImageDrawable(getResources().getDrawable(R.drawable.cookies_enabled));
+ firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_enabled));
} else { // First-party cookies are disabled.
firstPartyCookiesEnabledSwitch.setChecked(false);
// Set the icon according to the theme.
if (MainWebViewActivity.darkTheme) {
- firstPartyCookiesImageView.setImageDrawable(getResources().getDrawable(R.drawable.cookies_disabled_dark));
+ firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_dark));
} else {
- firstPartyCookiesImageView.setImageDrawable(getResources().getDrawable(R.drawable.cookies_disabled_light));
+ firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_light));
}
}
// Set the third-party cookies status. Once minimum API >= 21 we can use a selector as the tint mode instead of specifying different icons.
if (thirdPartyCookiesEnabledInt == 1) { // Both first-party and third-party cookies are enabled.
thirdPartyCookiesEnabledSwitch.setChecked(true);
- thirdPartyCookiesImageView.setImageDrawable(getResources().getDrawable(R.drawable.cookies_warning));
+ thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_warning));
} else { // First party cookies are enabled but third-party cookies are disabled.
thirdPartyCookiesEnabledSwitch.setChecked(false);
// Set the icon according to the theme.
if (MainWebViewActivity.darkTheme) {
- thirdPartyCookiesImageView.setImageDrawable(getResources().getDrawable(R.drawable.cookies_disabled_dark));
+ thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_dark));
} else {
- thirdPartyCookiesImageView.setImageDrawable(getResources().getDrawable(R.drawable.cookies_disabled_light));
+ thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_light));
}
}
} else { // First-party cookies are disabled.
// Set the icon according to the theme.
if (MainWebViewActivity.darkTheme) {
- thirdPartyCookiesImageView.setImageDrawable(getResources().getDrawable(R.drawable.cookies_ghosted_dark));
+ thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_ghosted_dark));
} else {
- thirdPartyCookiesImageView.setImageDrawable(getResources().getDrawable(R.drawable.cookies_ghosted_light));
+ thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_ghosted_light));
}
}
} else { // Third-party cookies cannot be configured for API <= 21.
// Set the DOM storage status. Once minimum API >= 21 we can use a selector as the tint mode instead of specifying different icons.
if (domStorageEnabledInt == 1) { // Both JavaScript and DOM storage are enabled.
domStorageEnabledSwitch.setChecked(true);
- domStorageImageView.setImageDrawable(getResources().getDrawable(R.drawable.dom_storage_enabled));
+ domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_enabled));
} else { // JavaScript is enabled but DOM storage is disabled.
// Set the DOM storage switch to off.
domStorageEnabledSwitch.setChecked(false);
// Set the icon according to the theme.
if (MainWebViewActivity.darkTheme) {
- domStorageImageView.setImageDrawable(getResources().getDrawable(R.drawable.dom_storage_disabled_dark));
+ domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_dark));
} else {
- domStorageImageView.setImageDrawable(getResources().getDrawable(R.drawable.dom_storage_disabled_light));
+ domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_light));
}
}
} else { // JavaScript is disabled.
// Set the icon according to the theme.
if (MainWebViewActivity.darkTheme) {
- domStorageImageView.setImageDrawable(getResources().getDrawable(R.drawable.dom_storage_ghosted_dark));
+ domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_dark));
} else {
- domStorageImageView.setImageDrawable(getResources().getDrawable(R.drawable.dom_storage_ghosted_light));
+ domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_light));
}
}
// Set the form data status. Once minimum API >= 21 we can use a selector as the tint mode instead of specifying different icons.
if (formDataEnabledInt == 1) { // Form data is enabled.
formDataEnabledSwitch.setChecked(true);
- formDataImageView.setImageDrawable(getResources().getDrawable(R.drawable.form_data_enabled));
+ formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_enabled));
} else { // Form data is disabled.
// Set the form data switch to off.
formDataEnabledSwitch.setChecked(false);
// Set the icon according to the theme.
if (MainWebViewActivity.darkTheme) {
- formDataImageView.setImageDrawable(getResources().getDrawable(R.drawable.form_data_disabled_dark));
+ formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_disabled_dark));
} else {
- formDataImageView.setImageDrawable(getResources().getDrawable(R.drawable.form_data_disabled_light));
+ formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_disabled_light));
}
}
WebView bareWebView = (WebView) bareWebViewLayout.findViewById(R.id.bare_webview);
final String webViewDefaultUserAgentString = bareWebView.getSettings().getUserAgentString();
- // Get a handle for the shared preference.
- SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
-
- // Store the default user agent string values.
- final String defaultUserAgentString = sharedPreferences.getString("user_agent", "PrivacyBrowser/1.0");
- final String defaultCustomUserAgentString = sharedPreferences.getString("custom_user_agent", "PrivacyBrowser/1.0");
-
// Get the position of the user agent in `userAgentEntryValuesArrayAdapter`.
int userAgentArrayPosition = userAgentEntryValuesArrayAdapter.getPosition(currentUserAgentString);
int fontSizeArrayPosition = fontSizeEntryValuesArrayAdapter.getPosition(String.valueOf(fontSizeInt));
fontSizeSpinner.setSelection(fontSizeArrayPosition);
+ // Set the default font size text.
+ int defaultFontSizeArrayPosition = fontSizeEntryValuesArrayAdapter.getPosition(defaultFontSizeString);
+ fontSizeTextView.setText(fontSizeArrayAdapter.getItem(defaultFontSizeArrayPosition));
+
+ // Set the display options for `fontSizeTextView`.
+ if (fontSizeArrayPosition == 0) { // System default font size is selected. Display `fontSizeTextView`.
+ fontSizeTextView.setVisibility(View.VISIBLE);
+ } else { // A custom font size is specified. Hide `fontSizeTextView`.
+ fontSizeTextView.setVisibility(View.GONE);
+ }
+
// Set the selected display website images mode.
displayWebpageImagesSpinner.setSelection(displayImagesInt);
- // Set the display website images icon.
+ // Set the default display images text.
+ if (defaultDisplayWebpageImagesBoolean) {
+ displayImagesTextView.setText(displayImagesArrayAdapter.getItem(1));
+ } else {
+ displayImagesTextView.setText(displayImagesArrayAdapter.getItem(2));
+ }
+
+ // Set the display website images icon and `TextView` settings.
switch (displayImagesInt) {
case DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_SYSTEM_DEFAULT:
if (MainWebViewActivity.displayWebpageImagesBoolean) {
// Set the icon according to the theme.
if (MainWebViewActivity.darkTheme) {
- displayWebpageImagesImageView.setImageDrawable(getResources().getDrawable(R.drawable.images_enabled_dark));
+ displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_dark));
} else {
- displayWebpageImagesImageView.setImageDrawable(getResources().getDrawable(R.drawable.images_enabled_light));
+ displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_light));
}
} else {
// Set the icon according to the theme.
if (MainWebViewActivity.darkTheme) {
- displayWebpageImagesImageView.setImageDrawable(getResources().getDrawable(R.drawable.images_disabled_dark));
+ displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_dark));
} else {
- displayWebpageImagesImageView.setImageDrawable(getResources().getDrawable(R.drawable.images_disabled_light));
+ displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_light));
}
}
+
+ // Show `displayImagesTextView`.
+ displayImagesTextView.setVisibility(View.VISIBLE);
break;
case DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_ENABLED:
// Set the icon according to the theme.
if (MainWebViewActivity.darkTheme) {
- displayWebpageImagesImageView.setImageDrawable(getResources().getDrawable(R.drawable.images_enabled_dark));
+ displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_dark));
} else {
- displayWebpageImagesImageView.setImageDrawable(getResources().getDrawable(R.drawable.images_enabled_light));
+ displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_light));
}
+
+ // Hide `displayImagesTextView`.
+ displayImagesTextView.setVisibility(View.GONE);
break;
case DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_DISABLED:
// Set the icon according to the theme.
if (MainWebViewActivity.darkTheme) {
- displayWebpageImagesImageView.setImageDrawable(getResources().getDrawable(R.drawable.images_disabled_dark));
+ displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_dark));
} else {
- displayWebpageImagesImageView.setImageDrawable(getResources().getDrawable(R.drawable.images_disabled_light));
+ displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_light));
}
+
+ // Hide `displayImagesTextView`.
+ displayImagesTextView.setVisibility(View.GONE);
break;
}
+
+ // Set the pinned SSL certificate icon.
+ if (pinnedSslCertificateInt == 1) { // Pinned SSL certificate is enabled.
+ // Check the switch.
+ pinnedSslCertificateSwitch.setChecked(true);
+
+ // Set the icon according to the theme.
+ if (MainWebViewActivity.darkTheme) {
+ pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_dark));
+ } else {
+ pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_light));
+ }
+ } else { // Pinned SSL certificate is disabled.
+ // Uncheck the switch.
+ pinnedSslCertificateSwitch.setChecked(false);
+
+ // Set the icon according to the theme.
+ if (MainWebViewActivity.darkTheme) {
+ pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_dark));
+ } else {
+ pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_light));
+ }
+ }
+
+ // Store the current date.
+ Date currentDate = Calendar.getInstance().getTime();
+
+ // Setup the `StringBuilders` to display the general certificate information in blue. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
+ savedSslCertificateIssuedToONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), savedSslCertificateIssuedToONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+ savedSslCertificateIssuedToUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), savedSslCertificateIssuedToUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+ savedSslCertificateIssuedByCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), savedSslCertificateIssuedByCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+ savedSslCertificateIssuedByONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), savedSslCertificateIssuedByONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+ savedSslCertificateIssuedByUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), savedSslCertificateIssuedByUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+
+ // Check the certificate `Common Name` against the domain name.
+ boolean savedSSlCertificateCommonNameMatchesDomainName = checkDomainNameAgainstCertificate(domainNameString, savedSslCertificateIssuedToCNameString);
+
+ // Format the `issuedToCommonName` color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
+ if (savedSSlCertificateCommonNameMatchesDomainName) {
+ savedSslCertificateIssuedToCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), savedSslCertificateIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+ } else {
+ savedSslCertificateIssuedToCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), savedSslCertificateIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+ }
+
+ // Format the start date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
+ if ((savedSslCertificateStartDate != null) && savedSslCertificateStartDate.after(currentDate)) { // The certificate start date is in the future.
+ savedSslCertificateStartDateStringBuilder.setSpan(redColorSpan, startDateLabel.length(), savedSslCertificateStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+ } else { // The certificate start date is in the past.
+ savedSslCertificateStartDateStringBuilder.setSpan(blueColorSpan, startDateLabel.length(), savedSslCertificateStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+ }
+
+ // Format the end date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
+ if ((savedSslCertificateEndDate != null) && savedSslCertificateEndDate.before(currentDate)) { // The certificate end date is in the past.
+ savedSslCertificateEndDateStringBuilder.setSpan(redColorSpan, endDateLabel.length(), savedSslCertificateEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+ } else { // The certificate end date is in the future.
+ savedSslCertificateEndDateStringBuilder.setSpan(blueColorSpan, endDateLabel.length(), savedSslCertificateEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+ }
+
+ // Display the current website SSL certificate strings.
+ savedSslCertificateIssuedToCNameTextView.setText(savedSslCertificateIssuedToCNameStringBuilder);
+ savedSslCertificateIssuedToONameTextView.setText(savedSslCertificateIssuedToONameStringBuilder);
+ savedSslCertificateIssuedToUNameTextView.setText(savedSslCertificateIssuedToUNameStringBuilder);
+ savedSslCertificateIssuedByCNameTextView.setText(savedSslCertificateIssuedByCNameStringBuilder);
+ savedSslCertificateIssuedByONameTextView.setText(savedSslCertificateIssuedByONameStringBuilder);
+ savedSslCertificateIssuedByUNameTextView.setText(savedSslCertificateIssuedByUNameStringBuilder);
+ savedSslCertificateStartDateTextView.setText(savedSslCertificateStartDateStringBuilder);
+ savedSslCertificateEndDateTextView.setText(savedSslCertificateEndDateStringBuilder);
+
+ // Populate the current website SSL certificate if there is one.
+ if (currentWebsiteSslCertificate != null) {
+ // Get the strings from the SSL certificate.
+ String currentWebsiteCertificateIssuedToCNameString = currentWebsiteSslCertificate.getIssuedTo().getCName();
+ String currentWebsiteCertificateIssuedToONameString = currentWebsiteSslCertificate.getIssuedTo().getOName();
+ String currentWebsiteCertificateIssuedToUNameString = currentWebsiteSslCertificate.getIssuedTo().getUName();
+ String currentWebsiteCertificateIssuedByCNameString = currentWebsiteSslCertificate.getIssuedBy().getCName();
+ String currentWebsiteCertificateIssuedByONameString = currentWebsiteSslCertificate.getIssuedBy().getOName();
+ String currentWebsiteCertificateIssuedByUNameString = currentWebsiteSslCertificate.getIssuedBy().getUName();
+ Date currentWebsiteCertificateStartDate = currentWebsiteSslCertificate.getValidNotBeforeDate();
+ Date currentWebsiteCertificateEndDate = currentWebsiteSslCertificate.getValidNotAfterDate();
+
+ // Create a `SpannableStringBuilder` for each `TextView` that needs multiple colors of text.
+ SpannableStringBuilder currentWebsiteCertificateIssuedToCNameStringBuilder = new SpannableStringBuilder(cNameLabel + currentWebsiteCertificateIssuedToCNameString);
+ SpannableStringBuilder currentWebsiteCertificateIssuedToONameStringBuilder = new SpannableStringBuilder(oNameLabel + currentWebsiteCertificateIssuedToONameString);
+ SpannableStringBuilder currentWebsiteCertificateIssuedToUNameStringBuilder = new SpannableStringBuilder(uNameLabel + currentWebsiteCertificateIssuedToUNameString);
+ SpannableStringBuilder currentWebsiteCertificateIssuedByCNameStringBuilder = new SpannableStringBuilder(cNameLabel + currentWebsiteCertificateIssuedByCNameString);
+ SpannableStringBuilder currentWebsiteCertificateIssuedByONameStringBuilder = new SpannableStringBuilder(oNameLabel + currentWebsiteCertificateIssuedByONameString);
+ SpannableStringBuilder currentWebsiteCertificateIssuedByUNameStringBuilder = new SpannableStringBuilder(uNameLabel + currentWebsiteCertificateIssuedByUNameString);
+ SpannableStringBuilder currentWebsiteCertificateStartDateStringBuilder = new SpannableStringBuilder(startDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(currentWebsiteCertificateStartDate));
+ SpannableStringBuilder currentWebsiteCertificateEndDateStringBuilder = new SpannableStringBuilder(endDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(currentWebsiteCertificateEndDate));
+
+ // Setup the `StringBuilders` to display the general certificate information in blue. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
+ currentWebsiteCertificateIssuedToONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), currentWebsiteCertificateIssuedToONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+ currentWebsiteCertificateIssuedToUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), currentWebsiteCertificateIssuedToUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+ currentWebsiteCertificateIssuedByCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), currentWebsiteCertificateIssuedByCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+ currentWebsiteCertificateIssuedByONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), currentWebsiteCertificateIssuedByONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+ currentWebsiteCertificateIssuedByUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), currentWebsiteCertificateIssuedByUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+
+ // Check the certificate `Common Name` against the domain name.
+ boolean currentWebsiteCertificateCommonNameMatchesDomainName = checkDomainNameAgainstCertificate(domainNameString, currentWebsiteCertificateIssuedToCNameString);
+
+ // Format the `issuedToCommonName` color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
+ if (currentWebsiteCertificateCommonNameMatchesDomainName) {
+ currentWebsiteCertificateIssuedToCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), currentWebsiteCertificateIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+ } else {
+ currentWebsiteCertificateIssuedToCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), currentWebsiteCertificateIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+ }
+
+ // Format the start date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
+ if (currentWebsiteCertificateStartDate.after(currentDate)) { // The certificate start date is in the future.
+ currentWebsiteCertificateStartDateStringBuilder.setSpan(redColorSpan, startDateLabel.length(), currentWebsiteCertificateStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+ } else { // The certificate start date is in the past.
+ currentWebsiteCertificateStartDateStringBuilder.setSpan(blueColorSpan, startDateLabel.length(), currentWebsiteCertificateStartDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+ }
+
+ // Format the end date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
+ if (currentWebsiteCertificateEndDate.before(currentDate)) { // The certificate end date is in the past.
+ currentWebsiteCertificateEndDateStringBuilder.setSpan(redColorSpan, endDateLabel.length(), currentWebsiteCertificateEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+ } else { // The certificate end date is in the future.
+ currentWebsiteCertificateEndDateStringBuilder.setSpan(blueColorSpan, endDateLabel.length(), currentWebsiteCertificateEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+ }
+
+ // Display the current website SSL certificate strings.
+ currentWebsiteCertificateIssuedToCNameTextView.setText(currentWebsiteCertificateIssuedToCNameStringBuilder);
+ currentWebsiteCertificateIssuedToONameTextView.setText(currentWebsiteCertificateIssuedToONameStringBuilder);
+ currentWebsiteCertificateIssuedToUNameTextView.setText(currentWebsiteCertificateIssuedToUNameStringBuilder);
+ currentWebsiteCertificateIssuedByCNameTextView.setText(currentWebsiteCertificateIssuedByCNameStringBuilder);
+ currentWebsiteCertificateIssuedByONameTextView.setText(currentWebsiteCertificateIssuedByONameStringBuilder);
+ currentWebsiteCertificateIssuedByUNameTextView.setText(currentWebsiteCertificateIssuedByUNameStringBuilder);
+ currentWebsiteCertificateStartDateTextView.setText(currentWebsiteCertificateStartDateStringBuilder);
+ currentWebsiteCertificateEndDateTextView.setText(currentWebsiteCertificateEndDateStringBuilder);
+ }
+
+ // Set the initial display status for the SSL certificates.
+ if (pinnedSslCertificateSwitch.isChecked()) {
+ // Set the visibility of the saved SSL certificate.
+ if (savedSslCertificateIssuedToCNameString == null) {
+ savedSslCertificateLinearLayout.setVisibility(View.GONE);
+ } else {
+ savedSslCertificateLinearLayout.setVisibility(View.VISIBLE);
+ }
+
+ // Set the visibility of the current website SSL certificate.
+ if (currentWebsiteSslCertificate == null) {
+ // Hide the SSL certificate.
+ currentWebsiteCertificateLinearLayout.setVisibility(View.GONE);
+
+ // Show the instruction.
+ noCurrentWebsiteCertificateTextView.setVisibility(View.VISIBLE);
+ } else {
+ // Show the SSL certificate.
+ currentWebsiteCertificateLinearLayout.setVisibility(View.VISIBLE);
+
+ // Hide the instruction.
+ noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
+ }
+
+ // Set the status of the radio buttons.
+ if (savedSslCertificateLinearLayout.getVisibility() == View.VISIBLE) { // The saved SSL certificate is displayed.
+ savedSslCertificateRadioButton.setChecked(true);
+ currentWebsiteCertificateRadioButton.setChecked(false);
+ } else if (currentWebsiteCertificateLinearLayout.getVisibility() == View.VISIBLE) { // The saved SSL certificate is hidden but the current website SSL certificate is visible.
+ currentWebsiteCertificateRadioButton.setChecked(true);
+ savedSslCertificateRadioButton.setChecked(false);
+ } else { // Neither SSL certificate is visible.
+ savedSslCertificateRadioButton.setChecked(false);
+ currentWebsiteCertificateRadioButton.setChecked(false);
+ }
+ } else { // `pinnedSslCertificateSwitch` is not checked.
+ // Hide the SSl certificates and instructions.
+ savedSslCertificateLinearLayout.setVisibility(View.GONE);
+ currentWebsiteCertificateLinearLayout.setVisibility(View.GONE);
+ noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
+
+ // Uncheck the radio buttons.
+ savedSslCertificateRadioButton.setChecked(false);
+ currentWebsiteCertificateRadioButton.setChecked(false);
+ }
// Set the `javaScriptEnabledSwitch` `OnCheckedChangeListener()`.
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) { // JavaScript is enabled.
// Update the JavaScript icon.
- javaScriptImageView.setImageDrawable(getResources().getDrawable(R.drawable.javascript_enabled));
+ javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.javascript_enabled));
// Enable the DOM storage `Switch`.
domStorageEnabledSwitch.setEnabled(true);
// Update the DOM storage icon.
if (domStorageEnabledSwitch.isChecked()) { // DOM storage is enabled.
- domStorageImageView.setImageDrawable(getResources().getDrawable(R.drawable.dom_storage_enabled));
+ domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_enabled));
} else { // DOM storage is disabled.
// Set the icon according to the theme.
if (MainWebViewActivity.darkTheme) {
- domStorageImageView.setImageDrawable(getResources().getDrawable(R.drawable.dom_storage_disabled_dark));
+ domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_dark));
} else {
- domStorageImageView.setImageDrawable(getResources().getDrawable(R.drawable.dom_storage_disabled_light));
+ domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_light));
}
}
} else { // JavaScript is disabled.
// Update the JavaScript icon.
- javaScriptImageView.setImageDrawable(getResources().getDrawable(R.drawable.privacy_mode));
+ javaScriptImageView.setImageDrawable(resources.getDrawable(R.drawable.privacy_mode));
// Disable the DOM storage `Switch`.
domStorageEnabledSwitch.setEnabled(false);
// Set the DOM storage icon according to the theme.
if (MainWebViewActivity.darkTheme) {
- domStorageImageView.setImageDrawable(getResources().getDrawable(R.drawable.dom_storage_ghosted_dark));
+ domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_dark));
} else {
- domStorageImageView.setImageDrawable(getResources().getDrawable(R.drawable.dom_storage_ghosted_light));
+ domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_ghosted_light));
}
}
}
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) { // First-party cookies are enabled.
// Update the first-party cookies icon.
- firstPartyCookiesImageView.setImageDrawable(getResources().getDrawable(R.drawable.cookies_enabled));
+ firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_enabled));
// Enable the third-party cookies `Switch`.
thirdPartyCookiesEnabledSwitch.setEnabled(true);
// Update the third-party cookies icon.
if (thirdPartyCookiesEnabledSwitch.isChecked()) { // Third-party cookies are enabled.
- thirdPartyCookiesImageView.setImageDrawable(getResources().getDrawable(R.drawable.cookies_warning));
+ thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_warning));
} else { // Third-party cookies are disabled.
// Set the third-party cookies icon according to the theme.
if (MainWebViewActivity.darkTheme) {
- thirdPartyCookiesImageView.setImageDrawable(getResources().getDrawable(R.drawable.cookies_disabled_dark));
+ thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_dark));
} else {
- thirdPartyCookiesImageView.setImageDrawable(getResources().getDrawable(R.drawable.cookies_disabled_light));
+ thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_light));
}
}
} else { // First-party cookies are disabled.
// Update the first-party cookies icon according to the theme.
if (MainWebViewActivity.darkTheme) {
- firstPartyCookiesImageView.setImageDrawable(getResources().getDrawable(R.drawable.cookies_disabled_dark));
+ firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_dark));
} else {
- firstPartyCookiesImageView.setImageDrawable(getResources().getDrawable(R.drawable.cookies_disabled_light));
+ firstPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_light));
}
// Disable the third-party cookies `Switch`.
// Set the third-party cookies icon according to the theme.
if (MainWebViewActivity.darkTheme) {
- thirdPartyCookiesImageView.setImageDrawable(getResources().getDrawable(R.drawable.cookies_ghosted_dark));
+ thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_ghosted_dark));
} else {
- thirdPartyCookiesImageView.setImageDrawable(getResources().getDrawable(R.drawable.cookies_ghosted_light));
+ thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_ghosted_light));
}
}
}
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
// Update the icon.
if (isChecked) {
- thirdPartyCookiesImageView.setImageDrawable(getResources().getDrawable(R.drawable.cookies_warning));
+ thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_warning));
} else {
// Update the third-party cookies icon according to the theme.
if (MainWebViewActivity.darkTheme) {
- thirdPartyCookiesImageView.setImageDrawable(getResources().getDrawable(R.drawable.cookies_disabled_dark));
+ thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_dark));
} else {
- thirdPartyCookiesImageView.setImageDrawable(getResources().getDrawable(R.drawable.cookies_disabled_light));
+ thirdPartyCookiesImageView.setImageDrawable(resources.getDrawable(R.drawable.cookies_disabled_light));
}
}
}
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
// Update the icon.
if (isChecked) {
- domStorageImageView.setImageDrawable(getResources().getDrawable(R.drawable.dom_storage_enabled));
+ domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_enabled));
} else {
// Set the icon according to the theme.
if (MainWebViewActivity.darkTheme) {
- domStorageImageView.setImageDrawable(getResources().getDrawable(R.drawable.dom_storage_disabled_dark));
+ domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_dark));
} else {
- domStorageImageView.setImageDrawable(getResources().getDrawable(R.drawable.dom_storage_disabled_light));
+ domStorageImageView.setImageDrawable(resources.getDrawable(R.drawable.dom_storage_disabled_light));
}
}
}
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
// Update the icon.
if (isChecked) {
- formDataImageView.setImageDrawable(getResources().getDrawable(R.drawable.form_data_enabled));
+ formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_enabled));
} else {
// Set the icon according to the theme.
if (MainWebViewActivity.darkTheme) {
- formDataImageView.setImageDrawable(getResources().getDrawable(R.drawable.form_data_disabled_dark));
+ formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_disabled_dark));
} else {
- formDataImageView.setImageDrawable(getResources().getDrawable(R.drawable.form_data_disabled_light));
+ formDataImageView.setImageDrawable(resources.getDrawable(R.drawable.form_data_disabled_light));
}
}
}
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
// Store the new user agent string.
- String newUserAgentString = getResources().getStringArray(R.array.domain_settings_user_agent_entry_values)[position];
+ String newUserAgentString = resources.getStringArray(R.array.domain_settings_user_agent_entry_values)[position];
// Set the new user agent.
switch (newUserAgentString) {
}
});
- // Set the `displayImagesSwitch` `onItemClickListener()`.
+ // Set the `fontSizeSpinner` `onItemSelectedListener()`.
+ fontSizeSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+ @Override
+ public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
+ // Update the display options for `fontSizeTextView`.
+ if (position == 0) { // System default font size has been selected. Display `fontSizeTextView`.
+ fontSizeTextView.setVisibility(View.VISIBLE);
+ } else { // A custom font size has been selected. Hide `fontSizeTextView`.
+ fontSizeTextView.setVisibility(View.GONE);
+ }
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView<?> parent) {
+ // Do nothing.
+ }
+ });
+
+ // Set the `displayWebpageImagesSpinner` `onItemSelectedListener()`.
displayWebpageImagesSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
- // Update the icon.
+ // Update the icon and the visibility of `displayImagesTextView`.
switch (position) {
case DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_SYSTEM_DEFAULT:
if (MainWebViewActivity.displayWebpageImagesBoolean) {
// Set the icon according to the theme.
if (MainWebViewActivity.darkTheme) {
- displayWebpageImagesImageView.setImageDrawable(getResources().getDrawable(R.drawable.images_enabled_dark));
+ displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_dark));
} else {
- displayWebpageImagesImageView.setImageDrawable(getResources().getDrawable(R.drawable.images_enabled_light));
+ displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_light));
}
} else {
// Set the icon according to the theme.
if (MainWebViewActivity.darkTheme) {
- displayWebpageImagesImageView.setImageDrawable(getResources().getDrawable(R.drawable.images_disabled_dark));
+ displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_dark));
} else {
- displayWebpageImagesImageView.setImageDrawable(getResources().getDrawable(R.drawable.images_disabled_light));
+ displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_light));
}
}
+
+ // Show `displayImagesTextView`.
+ displayImagesTextView.setVisibility(View.VISIBLE);
break;
case DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_ENABLED:
// Set the icon according to the theme.
if (MainWebViewActivity.darkTheme) {
- displayWebpageImagesImageView.setImageDrawable(getResources().getDrawable(R.drawable.images_enabled_dark));
+ displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_dark));
} else {
- displayWebpageImagesImageView.setImageDrawable(getResources().getDrawable(R.drawable.images_enabled_light));
+ displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_enabled_light));
}
+
+ // Hide `displayImagesTextView`.
+ displayImagesTextView.setVisibility(View.GONE);
break;
case DomainsDatabaseHelper.DISPLAY_WEBPAGE_IMAGES_DISABLED:
// Set the icon according to the theme.
if (MainWebViewActivity.darkTheme) {
- displayWebpageImagesImageView.setImageDrawable(getResources().getDrawable(R.drawable.images_disabled_dark));
+ displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_dark));
} else {
- displayWebpageImagesImageView.setImageDrawable(getResources().getDrawable(R.drawable.images_disabled_light));
+ displayWebpageImagesImageView.setImageDrawable(resources.getDrawable(R.drawable.images_disabled_light));
}
+
+ // Hide `displayImagesTextView`.
+ displayImagesTextView.setVisibility(View.GONE);
break;
}
}
// Do nothing.
}
});
+
+ // Set the `pinnedSSLCertificateSwitch` `onCheckedChangeListener()`.
+ pinnedSslCertificateSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
+ @Override
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ // Update the icon
+ if (isChecked) { // Pinned SSL certificate is enabled.
+ // Set the icon according to the theme.
+ if (MainWebViewActivity.darkTheme) {
+ pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_dark));
+ } else {
+ pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_light));
+ }
+
+ // Update the visibility of the saved SSL certificate.
+ if (savedSslCertificateIssuedToCNameString == null) {
+ savedSslCertificateLinearLayout.setVisibility(View.GONE);
+ } else {
+ savedSslCertificateLinearLayout.setVisibility(View.VISIBLE);
+ }
+
+ // Update the visibility of the current website SSL certificate.
+ if (currentWebsiteSslCertificate == null) {
+ // Hide the SSL certificate.
+ currentWebsiteCertificateLinearLayout.setVisibility(View.GONE);
+
+ // Show the instruction.
+ noCurrentWebsiteCertificateTextView.setVisibility(View.VISIBLE);
+ } else {
+ // Show the SSL certificate.
+ currentWebsiteCertificateLinearLayout.setVisibility(View.VISIBLE);
+
+ // Hide the instruction.
+ noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
+ }
+
+ // Set the status of the radio buttons.
+ if (savedSslCertificateLinearLayout.getVisibility() == View.VISIBLE) { // The saved SSL certificate is displayed.
+ savedSslCertificateRadioButton.setChecked(true);
+ currentWebsiteCertificateRadioButton.setChecked(false);
+ } else if (currentWebsiteCertificateLinearLayout.getVisibility() == View.VISIBLE) { // The saved SSL certificate is hidden but the current website SSL certificate is visible.
+ currentWebsiteCertificateRadioButton.setChecked(true);
+ savedSslCertificateRadioButton.setChecked(false);
+ } else { // Neither SSL certificate is visible.
+ savedSslCertificateRadioButton.setChecked(false);
+ currentWebsiteCertificateRadioButton.setChecked(false);
+ }
+ } else { // Pinned SSL certificate is disabled.
+ // Set the icon according to the theme.
+ if (MainWebViewActivity.darkTheme) {
+ pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_dark));
+ } else {
+ pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_light));
+ }
+
+ // Hide the SSl certificates and instructions.
+ savedSslCertificateLinearLayout.setVisibility(View.GONE);
+ currentWebsiteCertificateLinearLayout.setVisibility(View.GONE);
+ noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
+
+ // Uncheck the radio buttons.
+ savedSslCertificateRadioButton.setChecked(false);
+ currentWebsiteCertificateRadioButton.setChecked(false);
+ }
+ }
+ });
+
+ savedSslCertificateLinearLayout.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ savedSslCertificateRadioButton.setChecked(true);
+ currentWebsiteCertificateRadioButton.setChecked(false);
+ }
+ });
+
+ savedSslCertificateRadioButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ savedSslCertificateRadioButton.setChecked(true);
+ currentWebsiteCertificateRadioButton.setChecked(false);
+ }
+ });
+
+ currentWebsiteCertificateLinearLayout.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ currentWebsiteCertificateRadioButton.setChecked(true);
+ savedSslCertificateRadioButton.setChecked(false);
+ }
+ });
+
+ currentWebsiteCertificateRadioButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ currentWebsiteCertificateRadioButton.setChecked(true);
+ savedSslCertificateRadioButton.setChecked(false);
+ }
+ });
return domainSettingsView;
}
+
+ private boolean checkDomainNameAgainstCertificate(String domainName, String certificateCommonName) {
+ // Initialize `domainNamesMatch`.
+ boolean domainNamesMatch = false;
+
+ // Check if the domains match.
+ if (domainName.equals(certificateCommonName)) {
+ domainNamesMatch = true;
+ }
+
+ // Check various wildcard permutations if `domainName` and `certificateCommonName` are not empty. `noinspection ConstantCondition` removes Android Studio's incorrect lint warning that `domainName` can never be `null`.
+ //noinspection ConstantConditions
+ if ((domainName != null) && (certificateCommonName != null)) {
+ // If `domainName` starts with a wildcard, check the base domain against all the subdomains of `certificateCommonName`.
+ if (!domainNamesMatch && domainName.startsWith("*.") && (domainName.length() > 2)) {
+ // Remove the initial `*.`.
+ String baseDomainName = domainName.substring(2);
+
+ // Setup a copy of `certificateCommonName` to test subdomains.
+ String certificateCommonNameSubdomain = certificateCommonName;
+
+ // Check all the subdomains in `certificateCommonNameSubdomains` against `baseDomainName`.
+ while (!domainNamesMatch && certificateCommonNameSubdomain.contains(".")) { // Stop checking if we know that `domainNamesMatch` is `true` or if we run out of `.`.
+ // Test the `certificateCommonNameSubdomain` against `baseDomainName`.
+ if (certificateCommonNameSubdomain.equals(baseDomainName)) {
+ domainNamesMatch = true;
+ }
+
+ // Strip out the lowest subdomain of `certificateCommonNameSubdomain`.
+ try {
+ certificateCommonNameSubdomain = certificateCommonNameSubdomain.substring(certificateCommonNameSubdomain.indexOf(".") + 1);
+ } catch (IndexOutOfBoundsException e) { // `certificateCommonNameSubdomain` ends with `.`.
+ certificateCommonNameSubdomain = "";
+ }
+ }
+ }
+
+ // If `certificateCommonName` starts with a wildcard, check the base common name against all the subdomains of `domainName`.
+ if (!domainNamesMatch && certificateCommonName.startsWith("*.") && (certificateCommonName.length() > 2)) {
+ // Remove the initial `*.`.
+ String baseCertificateCommonName = certificateCommonName.substring(2);
+
+ // Setup a copy of `domainName` to test subdomains.
+ String domainNameSubdomain = domainName;
+
+ // Check all the subdomains in `domainNameSubdomain` against `baseCertificateCommonName`.
+ while (!domainNamesMatch && domainNameSubdomain.contains(".") && (domainNameSubdomain.length() > 2)) {
+ // Test the `domainNameSubdomain` against `baseCertificateCommonName`.
+ if (domainNameSubdomain.equals(baseCertificateCommonName)) {
+ domainNamesMatch = true;
+ }
+
+ // Strip out the lowest subdomain of `domainNameSubdomain`.
+ try {
+ domainNameSubdomain = domainNameSubdomain.substring(domainNameSubdomain.indexOf(".") + 1);
+ } catch (IndexOutOfBoundsException e) { // `domainNameSubdomain` ends with `.`.
+ domainNameSubdomain = "";
+ }
+ }
+ }
+
+ // If both names start with a wildcard, check if the root of one contains the root of the other.
+ if (!domainNamesMatch && domainName.startsWith("*.") && (domainName.length() > 2) && certificateCommonName.startsWith("*.") && (certificateCommonName.length() > 2)) {
+ // Remove the wildcards.
+ String rootDomainName = domainName.substring(2);
+ String rootCertificateCommonName = certificateCommonName.substring(2);
+
+ // Check if one name ends with the contents of the other. If so, there will be overlap in the their wildcard subdomains.
+ if (rootDomainName.endsWith(rootCertificateCommonName) || rootCertificateCommonName.endsWith(rootDomainName)) {
+ domainNamesMatch = true;
+ }
+ }
+ }
+
+ return domainNamesMatch;
+ }
}
package com.stoutner.privacybrowser.fragments;
+import android.net.http.SslCertificate;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
// We have to use `android.support.v4.app.Fragment` until minimum API >= 23. Otherwise we cannot call `getContext()`.
import android.widget.AdapterView;
import android.widget.EditText;
import android.widget.ListView;
+import android.widget.RadioButton;
import android.widget.Spinner;
import android.widget.Switch;
EditText customUserAgentEditText = (EditText) domainSettingsFragmentView.findViewById(R.id.domain_settings_custom_user_agent_edittext);
Spinner fontSizeSpinner = (Spinner) domainSettingsFragmentView.findViewById(R.id.domain_settings_font_size_spinner);
Spinner displayWebpageImagesSpinner = (Spinner) domainSettingsFragmentView.findViewById(R.id.domain_settings_display_webpage_images_spinner);
+ Switch pinnedSslCertificateSwitch = (Switch) domainSettingsFragmentView.findViewById(R.id.domain_settings_pinned_ssl_certificate_switch);
+ RadioButton savedSslCertificateRadioButton = (RadioButton) domainSettingsFragmentView.findViewById(R.id.saved_ssl_certificate_radiobutton);
+ RadioButton currentWebsiteCertificateRadioButton = (RadioButton) domainSettingsFragmentView.findViewById(R.id.current_website_certificate_radiobutton);
// Extract the data for the domain settings.
String domainNameString = domainNameEditText.getText().toString();
int userAgentPositionInt = userAgentSpinner.getSelectedItemPosition();
int fontSizePositionInt = fontSizeSpinner.getSelectedItemPosition();
int displayWebpageImagesInt = displayWebpageImagesSpinner.getSelectedItemPosition();
+ boolean pinnedSslCertificate = pinnedSslCertificateSwitch.isChecked();
// Get the data for the `Spinners` from the entry values string arrays.
String userAgentString = getResources().getStringArray(R.array.domain_settings_user_agent_entry_values)[userAgentPositionInt];
}
// Save the domain settings.
- domainsDatabaseHelper.saveDomain(DomainsActivity.currentDomainDatabaseId, domainNameString, javaScriptEnabledBoolean, firstPartyCookiesEnabledBoolean, thirdPartyCookiesEnabledBoolean, domStorageEnabledEnabledBoolean, formDataEnabledBoolean, userAgentString, fontSizeInt,
- displayWebpageImagesInt);
+ if (savedSslCertificateRadioButton.isChecked()) { // The current certificate is being used.
+ // Update the database except for the certificate.
+ domainsDatabaseHelper.updateDomainExceptCertificate(DomainsActivity.currentDomainDatabaseId, domainNameString, javaScriptEnabledBoolean, firstPartyCookiesEnabledBoolean, thirdPartyCookiesEnabledBoolean, domStorageEnabledEnabledBoolean,
+ formDataEnabledBoolean, userAgentString, fontSizeInt, displayWebpageImagesInt, pinnedSslCertificate);
+ } else if (currentWebsiteCertificateRadioButton.isChecked()) { // The certificate is being updated with the current website certificate.
+ // Get the current website SSL certificate.
+ SslCertificate currentWebsiteSslCertificate = MainWebViewActivity.sslCertificate;
+
+ // Store the values from the SSL certificate.
+ String issuedToCommonName = currentWebsiteSslCertificate.getIssuedTo().getCName();
+ String issuedToOrganization = currentWebsiteSslCertificate.getIssuedTo().getOName();
+ String issuedToOrganizationalUnit = currentWebsiteSslCertificate.getIssuedTo().getUName();
+ String issuedByCommonName = currentWebsiteSslCertificate.getIssuedBy().getCName();
+ String issuedByOrganization = currentWebsiteSslCertificate.getIssuedBy().getOName();
+ String issuedByOrganizationalUnit = currentWebsiteSslCertificate.getIssuedBy().getUName();
+ long startDateLong = currentWebsiteSslCertificate.getValidNotBeforeDate().getTime();
+ long endDateLong = currentWebsiteSslCertificate.getValidNotAfterDate().getTime();
+
+ // Update the database.
+ domainsDatabaseHelper.updateDomainWithCertificate(DomainsActivity.currentDomainDatabaseId, domainNameString, javaScriptEnabledBoolean, firstPartyCookiesEnabledBoolean, thirdPartyCookiesEnabledBoolean, domStorageEnabledEnabledBoolean,
+ formDataEnabledBoolean, userAgentString, fontSizeInt, displayWebpageImagesInt, pinnedSslCertificate, issuedToCommonName, issuedToOrganization, issuedToOrganizationalUnit, issuedByCommonName, issuedByOrganization,
+ issuedByOrganizationalUnit, startDateLong, endDateLong);
+ } else { // No certificate is selected.
+ // Update the database, with PINNED_SSL_CERTIFICATE set to false.
+ domainsDatabaseHelper.updateDomainExceptCertificate(DomainsActivity.currentDomainDatabaseId, domainNameString, javaScriptEnabledBoolean, firstPartyCookiesEnabledBoolean, thirdPartyCookiesEnabledBoolean, domStorageEnabledEnabledBoolean,
+ formDataEnabledBoolean, userAgentString, fontSizeInt, displayWebpageImagesInt, false);
+ }
}
// Store the new `currentDomainDatabaseId`, converting it from `long` to `int` to match the format of the domains database.
import android.database.sqlite.SQLiteOpenHelper;
public class DomainsDatabaseHelper extends SQLiteOpenHelper {
- private static final int SCHEMA_VERSION = 2;
+ private static final int SCHEMA_VERSION = 3;
private static final String DOMAINS_DATABASE = "domains.db";
private static final String DOMAINS_TABLE = "domains";
public static final String USER_AGENT = "useragent";
public static final String FONT_SIZE = "fontsize";
public static final String DISPLAY_IMAGES = "displayimages";
+ public static final String PINNED_SSL_CERTIFICATE = "pinnedsslcertificate";
+ public static final String SSL_ISSUED_TO_COMMON_NAME = "sslissuedtocommonname";
+ public static final String SSL_ISSUED_TO_ORGANIZATION = "sslissuedtoorganization";
+ public static final String SSL_ISSUED_TO_ORGANIZATIONAL_UNIT = "sslissuedtoorganizationalunit";
+ public static final String SSL_ISSUED_BY_COMMON_NAME = "sslissuedbycommonname";
+ public static final String SSL_ISSUED_BY_ORGANIZATION = "sslissuedbyorganization";
+ public static final String SSL_ISSUED_BY_ORGANIZATIONAL_UNIT = "sslissuedbyorganizationalunit";
+ public static final String SSL_START_DATE = "sslstartdate";
+ public static final String SSL_END_DATE = "sslenddate";
public static final int DISPLAY_WEBPAGE_IMAGES_SYSTEM_DEFAULT = 0;
public static final int DISPLAY_WEBPAGE_IMAGES_ENABLED = 1;
@Override
public void onCreate(SQLiteDatabase domainsDatabase) {
// Setup the SQL string to create the `domains` table.
- final String CREATE_DOMAINS_TABLE = "CREATE TABLE " + DOMAINS_TABLE + " (" +
+ String CREATE_DOMAINS_TABLE = "CREATE TABLE " + DOMAINS_TABLE + " (" +
_ID + " INTEGER PRIMARY KEY, " +
DOMAIN_NAME + " TEXT, " +
ENABLE_JAVASCRIPT + " BOOLEAN, " +
ENABLE_FORM_DATA + " BOOLEAN, " +
USER_AGENT + " TEXT, " +
FONT_SIZE + " INTEGER, " +
- DISPLAY_IMAGES + " INTEGER);";
-
- // Create the `domains` table if it doesn't exist.
+ DISPLAY_IMAGES + " INTEGER, " +
+ PINNED_SSL_CERTIFICATE + " BOOLEAN, " +
+ SSL_ISSUED_TO_COMMON_NAME + " TEXT, " +
+ SSL_ISSUED_TO_ORGANIZATION + " TEXT, " +
+ SSL_ISSUED_TO_ORGANIZATIONAL_UNIT + " TEXT, " +
+ SSL_ISSUED_BY_COMMON_NAME + " TEXT, " +
+ SSL_ISSUED_BY_ORGANIZATION + " TEXT, " +
+ SSL_ISSUED_BY_ORGANIZATIONAL_UNIT + " TEXT, " +
+ SSL_START_DATE + " INTEGER, " +
+ SSL_END_DATE + " INTEGER);";
+
+ // Make it so.
domainsDatabase.execSQL(CREATE_DOMAINS_TABLE);
}
case 1:
// Add the `DISPLAY_IMAGES` column.
domainsDatabase.execSQL("ALTER TABLE " + DOMAINS_TABLE + " ADD COLUMN " + DISPLAY_IMAGES + " INTEGER");
+
+ // Upgrade from `SCHEMA_VERSION` 2.
+ case 2:
+ // Add the SSL certificate columns.
+ domainsDatabase.execSQL("ALTER TABLE " + DOMAINS_TABLE + " ADD COLUMN " + PINNED_SSL_CERTIFICATE + " BOOLEAN");
+ domainsDatabase.execSQL("ALTER TABLE " + DOMAINS_TABLE + " ADD COLUMN " + SSL_ISSUED_TO_COMMON_NAME + " TEXT");
+ domainsDatabase.execSQL("ALTER TABLE " + DOMAINS_TABLE + " ADD COLUMN " + SSL_ISSUED_TO_ORGANIZATION + " TEXT");
+ domainsDatabase.execSQL("ALTER TABLE " + DOMAINS_TABLE + " ADD COLUMN " + SSL_ISSUED_TO_ORGANIZATIONAL_UNIT + " TEXT");
+ domainsDatabase.execSQL("ALTER TABLE " + DOMAINS_TABLE + " ADD COLUMN " + SSL_ISSUED_BY_COMMON_NAME + " TEXT");
+ domainsDatabase.execSQL("ALTER TABLE " + DOMAINS_TABLE + " ADD COLUMN " + SSL_ISSUED_BY_ORGANIZATION + " TEXT");
+ domainsDatabase.execSQL("ALTER TABLE " + DOMAINS_TABLE + " ADD COLUMN " + SSL_ISSUED_BY_ORGANIZATIONAL_UNIT + " TEXT");
+ domainsDatabase.execSQL("ALTER TABLE " + DOMAINS_TABLE + " ADD COLUMN " + SSL_START_DATE + " INTEGER");
+ domainsDatabase.execSQL("ALTER TABLE " + DOMAINS_TABLE + " ADD COLUMN " + SSL_END_DATE + " INTEGER");
}
}
return newDomainDatabaseId;
}
- public void saveDomain(int databaseId, String domainName, boolean javaScriptEnabled, boolean firstPartyCookiesEnabled, boolean thirdPartyCookiesEnabled, boolean domStorageEnabled, boolean formDataEnabled, String userAgent, int fontSize,
- int displayImages) {
+ public void updateDomainExceptCertificate(int databaseId, String domainName, boolean javaScriptEnabled, boolean firstPartyCookiesEnabled, boolean thirdPartyCookiesEnabled, boolean domStorageEnabled, boolean formDataEnabled, String userAgent, int fontSize,
+ int displayImages, boolean pinnedSslCertificate) {
+ // Store the domain data in a `ContentValues`.
+ ContentValues domainContentValues = new ContentValues();
+
+ // Add entries for each field in the database.
+ domainContentValues.put(DOMAIN_NAME, domainName);
+ domainContentValues.put(ENABLE_JAVASCRIPT, javaScriptEnabled);
+ domainContentValues.put(ENABLE_FIRST_PARTY_COOKIES, firstPartyCookiesEnabled);
+ domainContentValues.put(ENABLE_THIRD_PARTY_COOKIES, thirdPartyCookiesEnabled);
+ domainContentValues.put(ENABLE_DOM_STORAGE, domStorageEnabled);
+ domainContentValues.put(ENABLE_FORM_DATA, formDataEnabled);
+ domainContentValues.put(USER_AGENT, userAgent);
+ domainContentValues.put(FONT_SIZE, fontSize);
+ domainContentValues.put(DISPLAY_IMAGES, displayImages);
+ domainContentValues.put(PINNED_SSL_CERTIFICATE, pinnedSslCertificate);
+
+ // Get a writable database handle.
+ SQLiteDatabase domainsDatabase = this.getWritableDatabase();
+
+ // Update the row for `databaseId`. The last argument is `null` because there are no `whereArgs`.
+ domainsDatabase.update(DOMAINS_TABLE, domainContentValues, _ID + " = " + databaseId, null);
+
+ // Close the database handle.
+ domainsDatabase.close();
+ }
+
+ public void updateDomainWithCertificate(int databaseId, String domainName, boolean javaScriptEnabled, boolean firstPartyCookiesEnabled, boolean thirdPartyCookiesEnabled, boolean domStorageEnabled, boolean formDataEnabled, String userAgent, int fontSize,
+ int displayImages, boolean pinnedSslCertificate, String sslIssuedToCommonName, String sslIssuedToOrganization, String sslIssuedToOrganizationalUnit, String sslIssuedByCommonName, String sslIssuedByOrganization,
+ String sslIssuedByOrganizationalUnit, long sslStartDate, long sslEndDate) {
// Store the domain data in a `ContentValues`.
ContentValues domainContentValues = new ContentValues();
domainContentValues.put(USER_AGENT, userAgent);
domainContentValues.put(FONT_SIZE, fontSize);
domainContentValues.put(DISPLAY_IMAGES, displayImages);
+ domainContentValues.put(PINNED_SSL_CERTIFICATE, pinnedSslCertificate);
+ domainContentValues.put(SSL_ISSUED_TO_COMMON_NAME, sslIssuedToCommonName);
+ domainContentValues.put(SSL_ISSUED_TO_ORGANIZATION, sslIssuedToOrganization);
+ domainContentValues.put(SSL_ISSUED_TO_ORGANIZATIONAL_UNIT, sslIssuedToOrganizationalUnit);
+ domainContentValues.put(SSL_ISSUED_BY_COMMON_NAME, sslIssuedByCommonName);
+ domainContentValues.put(SSL_ISSUED_BY_ORGANIZATION, sslIssuedByOrganization);
+ domainContentValues.put(SSL_ISSUED_BY_ORGANIZATIONAL_UNIT, sslIssuedByOrganizationalUnit);
+ domainContentValues.put(SSL_START_DATE, sslStartDate);
+ domainContentValues.put(SSL_END_DATE, sslEndDate);
+
+ // Get a writable database handle.
+ SQLiteDatabase domainsDatabase = this.getWritableDatabase();
+
+ // Update the row for `databaseId`. The last argument is `null` because there are no `whereArgs`.
+ domainsDatabase.update(DOMAINS_TABLE, domainContentValues, _ID + " = " + databaseId, null);
+
+ // Close the database handle.
+ domainsDatabase.close();
+ }
+
+ public void updateCertificate(int databaseId, String sslIssuedToCommonName, String sslIssuedToOrganization, String sslIssuedToOrganizationalUnit, String sslIssuedByCommonName, String sslIssuedByOrganization, String sslIssuedByOrganizationalUnit,
+ long sslStartDate, long sslEndDate) {
+ // Store the domain data in a `ContentValues`.
+ ContentValues domainContentValues = new ContentValues();
+
+ // Add entries for each field in the certificate.
+ domainContentValues.put(SSL_ISSUED_TO_COMMON_NAME, sslIssuedToCommonName);
+ domainContentValues.put(SSL_ISSUED_TO_ORGANIZATION, sslIssuedToOrganization);
+ domainContentValues.put(SSL_ISSUED_TO_ORGANIZATIONAL_UNIT, sslIssuedToOrganizationalUnit);
+ domainContentValues.put(SSL_ISSUED_BY_COMMON_NAME, sslIssuedByCommonName);
+ domainContentValues.put(SSL_ISSUED_BY_ORGANIZATION, sslIssuedByOrganization);
+ domainContentValues.put(SSL_ISSUED_BY_ORGANIZATIONAL_UNIT, sslIssuedByOrganizationalUnit);
+ domainContentValues.put(SSL_START_DATE, sslStartDate);
+ domainContentValues.put(SSL_END_DATE, sslEndDate);
// Get a writable database handle.
SQLiteDatabase domainsDatabase = this.getWritableDatabase();
--- /dev/null
+<!-- `ssl_certificate_enabled_dark.xml` comes from the Android Material icon set, where it is called `ic_vpn_lock`. It is released under the Apache License 2.0. -->
+
+<!-- `tools:ignore="VectorRaster"` removes the lint warning about `android:autoMirrored="true"` not applying to API < 21. -->
+<vector
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:height="24dp"
+ android:width="24dp"
+ android:viewportHeight="24.0"
+ android:viewportWidth="24.0"
+ android:autoMirrored="true"
+ tools:ignore="VectorRaster" >
+
+ <!-- We have to use a hard coded color until API >= 21. Then we can use `@color`. -->
+ <path
+ android:fillColor="#FF9E9E9E"
+ android:pathData="M22,4v-0.5C22,2.12 20.88,1 19.5,1S17,2.12 17,3.5L17,4c-0.55,0 -1,0.45 -1,1v4c0,0.55 0.45,1 1,1h5c0.55,0 1,-0.45 1,-1L23,5c0,-0.55 -0.45,-1 -1,-1zM21.2,4h-3.4v-0.5c0,-0.94 0.76,-1.7 1.7,-1.7s1.7,0.76 1.7,1.7L21.2,4zM18.92,12c0.04,0.33 0.08,0.66 0.08,1 0,2.08 -0.8,3.97 -2.1,5.39 -0.26,-0.81 -1,-1.39 -1.9,-1.39h-1v-3c0,-0.55 -0.45,-1 -1,-1L7,13v-2h2c0.55,0 1,-0.45 1,-1L10,8h2c1.1,0 2,-0.9 2,-2L14,3.46c-0.95,-0.3 -1.95,-0.46 -3,-0.46C5.48,3 1,7.48 1,13s4.48,10 10,10 10,-4.48 10,-10c0,-0.34 -0.02,-0.67 -0.05,-1h-2.03zM10,20.93c-3.95,-0.49 -7,-3.85 -7,-7.93 0,-0.62 0.08,-1.21 0.21,-1.79L8,16v1c0,1.1 0.9,2 2,2v1.93z" />
+</vector>
--- /dev/null
+<!-- `ssl_certificate_enabled_light.xml` comes from the Android Material icon set, where it is called `ic_vpn_lock`. It is released under the Apache License 2.0. -->
+
+<!-- `tools:ignore="VectorRaster"` removes the lint warning about `android:autoMirrored="true"` not applying to API < 21. -->
+<vector
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:height="24dp"
+ android:width="24dp"
+ android:viewportHeight="24.0"
+ android:viewportWidth="24.0"
+ android:autoMirrored="true"
+ tools:ignore="VectorRaster" >
+
+ <!-- We have to use a hard coded color until API >= 21. Then we can use `@color`. -->
+ <path
+ android:fillColor="#88000000"
+ android:pathData="M22,4v-0.5C22,2.12 20.88,1 19.5,1S17,2.12 17,3.5L17,4c-0.55,0 -1,0.45 -1,1v4c0,0.55 0.45,1 1,1h5c0.55,0 1,-0.45 1,-1L23,5c0,-0.55 -0.45,-1 -1,-1zM21.2,4h-3.4v-0.5c0,-0.94 0.76,-1.7 1.7,-1.7s1.7,0.76 1.7,1.7L21.2,4zM18.92,12c0.04,0.33 0.08,0.66 0.08,1 0,2.08 -0.8,3.97 -2.1,5.39 -0.26,-0.81 -1,-1.39 -1.9,-1.39h-1v-3c0,-0.55 -0.45,-1 -1,-1L7,13v-2h2c0.55,0 1,-0.45 1,-1L10,8h2c1.1,0 2,-0.9 2,-2L14,3.46c-0.95,-0.3 -1.95,-0.46 -3,-0.46C5.48,3 1,7.48 1,13s4.48,10 10,10 10,-4.48 10,-10c0,-0.34 -0.02,-0.67 -0.05,-1h-2.03zM10,20.93c-3.95,-0.49 -7,-3.85 -7,-7.93 0,-0.62 0.08,-1.21 0.21,-1.79L8,16v1c0,1.1 0.9,2 2,2v1.93z" />
+</vector>
--- /dev/null
+<!-- `ssl_certificate_enabled_dark.xml` comes from the Android Material icon set, where it is called `ic_vpn_lock`. It is released under the Apache License 2.0. -->
+
+<!-- `tools:ignore="VectorRaster"` removes the lint warning about `android:autoMirrored="true"` not applying to API < 21. -->
+<vector
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:height="24dp"
+ android:width="24dp"
+ android:viewportHeight="24.0"
+ android:viewportWidth="24.0"
+ android:autoMirrored="true"
+ tools:ignore="VectorRaster" >
+
+ <!-- We have to use a hard coded color until API >= 21. Then we can use `@color`. -->
+ <path
+ android:fillColor="#FF1E88E5"
+ android:pathData="M22,4v-0.5C22,2.12 20.88,1 19.5,1S17,2.12 17,3.5L17,4c-0.55,0 -1,0.45 -1,1v4c0,0.55 0.45,1 1,1h5c0.55,0 1,-0.45 1,-1L23,5c0,-0.55 -0.45,-1 -1,-1zM21.2,4h-3.4v-0.5c0,-0.94 0.76,-1.7 1.7,-1.7s1.7,0.76 1.7,1.7L21.2,4zM18.92,12c0.04,0.33 0.08,0.66 0.08,1 0,2.08 -0.8,3.97 -2.1,5.39 -0.26,-0.81 -1,-1.39 -1.9,-1.39h-1v-3c0,-0.55 -0.45,-1 -1,-1L7,13v-2h2c0.55,0 1,-0.45 1,-1L10,8h2c1.1,0 2,-0.9 2,-2L14,3.46c-0.95,-0.3 -1.95,-0.46 -3,-0.46C5.48,3 1,7.48 1,13s4.48,10 10,10 10,-4.48 10,-10c0,-0.34 -0.02,-0.67 -0.05,-1h-2.03zM10,20.93c-3.95,-0.49 -7,-3.85 -7,-7.93 0,-0.62 0.08,-1.21 0.21,-1.79L8,16v1c0,1.1 0.9,2 2,2v1.93z" />
+</vector>
--- /dev/null
+<!-- `ssl_certificate_enabled_light.xml` comes from the Android Material icon set, where it is called `ic_vpn_lock`. It is released under the Apache License 2.0. -->
+
+<!-- `tools:ignore="VectorRaster"` removes the lint warning about `android:autoMirrored="true"` not applying to API < 21. -->
+<vector
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:height="24dp"
+ android:width="24dp"
+ android:viewportHeight="24.0"
+ android:viewportWidth="24.0"
+ android:autoMirrored="true"
+ tools:ignore="VectorRaster" >
+
+ <!-- We have to use a hard coded color until API >= 21. Then we can use `@color`. -->
+ <path
+ android:fillColor="#FF1565C0"
+ android:pathData="M22,4v-0.5C22,2.12 20.88,1 19.5,1S17,2.12 17,3.5L17,4c-0.55,0 -1,0.45 -1,1v4c0,0.55 0.45,1 1,1h5c0.55,0 1,-0.45 1,-1L23,5c0,-0.55 -0.45,-1 -1,-1zM21.2,4h-3.4v-0.5c0,-0.94 0.76,-1.7 1.7,-1.7s1.7,0.76 1.7,1.7L21.2,4zM18.92,12c0.04,0.33 0.08,0.66 0.08,1 0,2.08 -0.8,3.97 -2.1,5.39 -0.26,-0.81 -1,-1.39 -1.9,-1.39h-1v-3c0,-0.55 -0.45,-1 -1,-1L7,13v-2h2c0.55,0 1,-0.45 1,-1L10,8h2c1.1,0 2,-0.9 2,-2L14,3.46c-0.95,-0.3 -1.95,-0.46 -3,-0.46C5.48,3 1,7.48 1,13s4.48,10 10,10 10,-4.48 10,-10c0,-0.34 -0.02,-0.67 -0.05,-1h-2.03zM10,20.93c-3.95,-0.49 -7,-3.85 -7,-7.93 0,-0.62 0.08,-1.21 0.21,-1.79L8,16v1c0,1.1 0.9,2 2,2v1.93z" />
+</vector>
<!-- `android:layout_weight="1"` makes `about_viewpager` fill the rest of the screen. -->
<android.support.v4.view.ViewPager
android:id="@+id/about_viewpager"
- android:layout_width="match_parent"
android:layout_height="0dp"
+ android:layout_width="match_parent"
android:layout_weight="1" />
</LinearLayout>
</android.support.design.widget.CoordinatorLayout>
\ No newline at end of file
android:text="@string/domain_name_already_exists"
android:textColor="?attr/redText"
android:layout_marginStart="8dp"
- android:layout_marginEnd="8dp"
- android:layout_marginBottom="12dp" />
+ android:layout_marginEnd="8dp" />
</LinearLayout>
\ No newline at end of file
android:id="@+id/domain_settings_javascript_imageview"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
+ android:layout_marginTop="1dp"
android:layout_marginEnd="10dp"
android:layout_gravity="center_vertical"
tools:ignore="contentDescription" />
<LinearLayout
android:layout_height="wrap_content"
android:layout_width="match_parent"
- android:orientation="horizontal" >
+ android:orientation="vertical"
+ android:layout_marginTop="14dp"
+ android:layout_marginBottom="14dp" >
- <ImageView
+ <LinearLayout
android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:layout_marginTop="1dp"
- android:layout_marginEnd="10dp"
- android:layout_gravity="center_vertical"
- android:src="@drawable/font_size_light"
- android:tint="?attr/iconTintColor"
- android:contentDescription="@string/font_size" />
+ android:layout_width="match_parent"
+ android:orientation="horizontal" >
- <Spinner
- android:id="@+id/domain_settings_font_size_spinner"
- android:layout_height="wrap_content"
+ <ImageView
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_marginTop="1dp"
+ android:layout_marginEnd="10dp"
+ android:layout_gravity="center_vertical"
+ android:src="@drawable/font_size_light"
+ android:tint="?attr/iconTintColor"
+ android:contentDescription="@string/font_size" />
+
+ <Spinner
+ android:id="@+id/domain_settings_font_size_spinner"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent" />
+ </LinearLayout>
+
+ <TextView
+ android:id="@+id/domain_settings_font_size_textview"
+ android:layout_height="match_parent"
android:layout_width="match_parent"
- android:layout_marginTop="14dp"
- android:layout_marginBottom="14dp" />
+ android:layout_marginStart="45dp"
+ android:layout_marginEnd="36dp"
+ android:textSize="13sp" />
+
</LinearLayout>
<!-- Display Images. -->
<LinearLayout
android:layout_height="wrap_content"
android:layout_width="match_parent"
- android:orientation="horizontal" >
+ android:orientation="vertical"
+ android:layout_marginTop="14dp"
+ android:layout_marginBottom="14dp" >
- <ImageView
- android:id="@+id/domain_settings_display_webpage_images_imageview"
+ <LinearLayout
android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:layout_marginTop="1dp"
- android:layout_marginEnd="10dp"
- android:layout_gravity="center_vertical"
- android:contentDescription="@string/display_webpage_images" />
+ android:layout_width="match_parent"
+ android:orientation="horizontal" >
+
+ <ImageView
+ android:id="@+id/domain_settings_display_webpage_images_imageview"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_marginTop="1dp"
+ android:layout_marginEnd="10dp"
+ android:layout_gravity="center_vertical"
+ android:contentDescription="@string/display_webpage_images" />
+
+ <Spinner
+ android:id="@+id/domain_settings_display_webpage_images_spinner"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent" />
+ </LinearLayout>
+
+ <TextView
+ android:id="@+id/domain_settings_display_webpage_images_textview"
+ android:layout_height="match_parent"
+ android:layout_width="match_parent"
+ android:layout_marginStart="45dp"
+ android:layout_marginEnd="36dp"
+ android:textSize="13sp" />
+ </LinearLayout>
+
+ <!-- Pinned SSL Certificate -->
+ <LinearLayout
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:orientation="vertical"
+ android:layout_marginTop="18dp"
+ android:layout_marginBottom="32dp" >
- <Spinner
- android:id="@+id/domain_settings_display_webpage_images_spinner"
+ <!-- Switch -->
+ <LinearLayout
android:layout_height="wrap_content"
android:layout_width="match_parent"
- android:layout_marginTop="14dp"
- android:layout_marginBottom="14dp" />
+ android:orientation="horizontal" >
+
+ <ImageView
+ android:id="@+id/domain_settings_pinned_ssl_certificate_imageview"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_marginTop="1dp"
+ android:layout_marginEnd="10dp"
+ android:layout_gravity="center_vertical"
+ tools:ignore="contentDescription" />
+
+ <Switch
+ android:id="@+id/domain_settings_pinned_ssl_certificate_switch"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:layout_marginStart="8dp"
+ android:text="@string/pinned_ssl_certificate"
+ android:textColor="?attr/primaryTextColorSelector"
+ android:textSize="18sp" />
+ </LinearLayout>
+
+ <!-- Saved Certificate -->
+ <LinearLayout
+ android:id="@+id/saved_ssl_certificate_linearlayout"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:orientation="vertical"
+ android:layout_marginTop="20dp"
+ android:layout_marginBottom="12dp"
+ android:layout_marginStart="10dp"
+ android:layout_marginEnd="10dp" >
+
+ <RadioButton
+ android:id="@+id/saved_ssl_certificate_radiobutton"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:text="@string/saved_ssl_certificate"
+ android:textSize="17sp"
+ android:textAllCaps="true"
+ android:textStyle="bold" />
+
+ <LinearLayout
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:layout_marginStart="32dp"
+ android:orientation="vertical" >
+
+ <!-- Saved Certificate Issued To. -->
+ <TextView
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:text="@string/issued_to"
+ android:textAllCaps="true"
+ android:textStyle="bold"
+ android:textColor="?attr/sslTitle" />
+
+ <TextView
+ android:id="@+id/saved_ssl_certificate_issued_to_cname"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent" />
+
+ <TextView
+ android:id="@+id/saved_ssl_certificate_issued_to_oname"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent" />
+
+ <TextView
+ android:id="@+id/saved_ssl_certificate_issued_to_uname"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"/>
+
+ <!-- Saved Certificate Issued By. -->
+ <TextView
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:layout_marginTop="15dp"
+ android:text="@string/issued_by"
+ android:textAllCaps="true"
+ android:textStyle="bold"
+ android:textColor="?attr/sslTitle"/>
+
+ <TextView
+ android:id="@+id/saved_ssl_certificate_issued_by_cname"
+
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent" />
+
+ <TextView
+ android:id="@+id/saved_ssl_certificate_issued_by_oname"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent" />
+
+ <TextView
+ android:id="@+id/saved_ssl_certificate_issued_by_uname"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent" />
+
+ <!-- Saved Certificate Valid Dates. -->
+ <TextView
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:layout_marginTop="15dp"
+ android:text="@string/valid_dates"
+ android:textAllCaps="true"
+ android:textStyle="bold"
+ android:textColor="?attr/sslTitle"/>
+
+ <TextView
+ android:id="@+id/saved_ssl_certificate_start_date"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent" />
+
+ <TextView
+ android:id="@+id/saved_ssl_certificate_end_date"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent" />
+ </LinearLayout>
+ </LinearLayout>
+
+ <!-- Current Website Certificate -->
+ <LinearLayout
+ android:id="@+id/current_website_certificate_linearlayout"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:orientation="vertical"
+ android:layout_marginTop="20dp"
+ android:layout_marginBottom="8dp"
+ android:layout_marginStart="10dp"
+ android:layout_marginEnd="10dp" >
+
+ <RadioButton
+ android:id="@+id/current_website_certificate_radiobutton"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:text="@string/current_website_ssl_certificate"
+ android:textSize="17sp"
+ android:textAllCaps="true"
+ android:textStyle="bold" />
+
+ <LinearLayout
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:layout_marginStart="32dp"
+ android:orientation="vertical" >
+
+ <!-- Current Website Certificate Issued To. -->
+ <TextView
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:text="@string/issued_to"
+ android:textAllCaps="true"
+ android:textStyle="bold"
+ android:textColor="?attr/sslTitle" />
+
+ <TextView
+ android:id="@+id/current_website_certificate_issued_to_cname"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent" />
+
+ <TextView
+ android:id="@+id/current_website_certificate_issued_to_oname"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent" />
+
+ <TextView
+ android:id="@+id/current_website_certificate_issued_to_uname"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent" />
+
+ <!-- Current Website Certificate Issued By. -->
+ <TextView
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:layout_marginTop="15dp"
+ android:text="@string/issued_by"
+ android:textAllCaps="true"
+ android:textStyle="bold"
+ android:textColor="?attr/sslTitle" />
+
+ <TextView
+ android:id="@+id/current_website_certificate_issued_by_cname"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent" />
+
+ <TextView
+ android:id="@+id/current_website_certificate_issued_by_oname"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent" />
+
+ <TextView
+ android:id="@+id/current_website_certificate_issued_by_uname"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent" />
+
+ <!-- Current Website Certificate Valid Dates. -->
+ <TextView
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:layout_marginTop="15dp"
+ android:text="@string/valid_dates"
+ android:textAllCaps="true"
+ android:textStyle="bold"
+ android:textColor="?attr/sslTitle" />
+
+ <TextView
+ android:id="@+id/current_website_certificate_start_date"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent" />
+
+ <TextView
+ android:id="@+id/current_website_certificate_end_date"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent" />
+ </LinearLayout>
+ </LinearLayout>
+
+ <!-- Load An Encrypted Website Instructions. -->
+ <TextView
+ android:id="@+id/no_current_website_certificate"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:layout_marginTop="10dp"
+ android:layout_marginStart="40dp"
+ android:layout_marginEnd="40dp"
+ android:gravity="center_horizontal"
+ android:text="@string/load_an_encrypted_website" />
</LinearLayout>
</LinearLayout>
</ScrollView>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ Copyright © 2017 Soren Stoutner <soren@stoutner.com>.
+
+ This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
+
+ Privacy Browser is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Privacy Browser is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Privacy Browser. If not, see <http://www.gnu.org/licenses/>. -->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:android.support.design="http://schemas.android.com/apk/res-auto"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:orientation="vertical">
+
+ <android.support.design.widget.TabLayout
+ android:id="@+id/pinned_ssl_certificate_mismatch_tablayout"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android.support.design:tabMode="scrollable"
+ android:theme="?attr/dialogTabLayoutTheme" />
+
+ <com.stoutner.privacybrowser.definitions.WrapVerticalContentViewPager
+ android:id="@+id/pinned_ssl_certificate_mismatch_viewpager"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content" />
+</LinearLayout>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ Copyright © 2017 Soren Stoutner <soren@stoutner.com>.
+
+ This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
+
+ Privacy Browser is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Privacy Browser is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Privacy Browser. If not, see <http://www.gnu.org/licenses/>. -->
+
+<ScrollView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content" >
+
+ <LinearLayout
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:padding="10dp"
+ android:orientation="vertical" >
+
+ <!-- Issued To. -->
+ <TextView
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:text="@string/issued_to"
+ android:textAllCaps="true"
+ android:textStyle="bold"
+ android:textColor="?attr/sslTitle" />
+
+ <TextView
+ android:id="@+id/issued_to_cname"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content" />
+
+ <TextView
+ android:id="@+id/issued_to_oname"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content" />
+
+ <TextView
+ android:id="@+id/issued_to_uname"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content" />
+
+
+ <!-- Issued By. -->
+ <TextView
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_marginTop="15dp"
+ android:text="@string/issued_by"
+ android:textAllCaps="true"
+ android:textStyle="bold"
+ android:textColor="?attr/sslTitle" />
+
+ <TextView
+ android:id="@+id/issued_by_cname"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content" />
+
+ <TextView
+ android:id="@+id/issued_by_oname"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content" />
+
+ <TextView
+ android:id="@+id/issued_by_uname"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content" />
+
+
+ <!-- Valid Dates. -->
+ <TextView
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_marginTop="15dp"
+ android:text="@string/valid_dates"
+ android:textAllCaps="true"
+ android:textStyle="bold"
+ android:textColor="?attr/sslTitle" />
+
+ <TextView
+ android:id="@+id/start_date"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content" />
+
+ <TextView
+ android:id="@+id/end_date"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content" />
+ </LinearLayout>
+</ScrollView>
\ No newline at end of file
<!-- Issued To. -->
<TextView
- android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
android:text="@string/issued_to"
android:textAllCaps="true"
android:textStyle="bold"
<TextView
android:id="@+id/issued_to_uname"
android:layout_height="wrap_content"
- android:layout_width="wrap_content"/>
+ android:layout_width="wrap_content" />
<!-- Issued By. -->
<TextView
- android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
android:layout_marginTop="15dp"
android:text="@string/issued_by"
android:textAllCaps="true"
android:textStyle="bold"
- android:textColor="?attr/sslTitle"/>
+ android:textColor="?attr/sslTitle" />
<TextView
android:id="@+id/issued_by_cname"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" />
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content" />
<TextView
android:id="@+id/issued_by_oname"
android:text="@string/valid_dates"
android:textAllCaps="true"
android:textStyle="bold"
- android:textColor="?attr/sslTitle"/>
+ android:textColor="?attr/sslTitle" />
<TextView
android:id="@+id/start_date"
<string name="domains">Dominios</string>
<string name="domain_settings">Configuración de dominio</string>
<string name="add_domain">Añadir dominio</string>
+ <string name="domain_name_already_exists">El nombre de dominio ya existe</string>
<string name="add">Añadir</string>
<string name="domain_name">Nombre de dominio</string>
<string name="domain_settings_saved">Configuración de dominio guardada</string>
<string name="domains">Domini</string>
<string name="domain_settings">Impostazioni Domini</string>
<string name="add_domain">Aggiungi Dominio</string>
+ <string name="domain_name_already_exists">Il nome del Dominio è già esistente</string>
<string name="add">Aggiungi</string>
<string name="domain_name">Nome del Dominio</string>
<string name="domain_settings_saved">Impostazioni Domini Salvate</string>
<attr name="appBarTextTheme" format="reference" />
<attr name="popupsTheme" format="reference" />
<attr name="tabLayoutTheme" format="reference" />
+ <attr name="dialogTabLayoutTheme" format="reference" />
<attr name="aboutTitle" format="reference" />
<attr name="aboutText" format="reference" />
<attr name="sslTitle" format="reference" />
+ <attr name="sslHeader" format="reference" />
<attr name="urlHistoryText" format="reference" />
<attr name="primaryTextColorSelector" format="reference" />
<attr name="redText" format="reference" />
<color name="blue_500">#FF2196F3</color>
<color name="blue_600">#FF1E88E5</color>
<color name="blue_700">#FF1976D2</color>
+ <color name="blue_700_50">#881976D2</color>
<color name="blue_800">#FF1565C0</color>
<color name="blue_900">#FF0D47A1</color>
<color name="blue_1000">#FF082B61</color>
<string name="url">URL</string>
<string name="url_label">URL:</string>
+ <!-- Pinned SSL Certificate Mismatch. -->
+ <string name="update_ssl">Update SSL</string>
+ <string name="ssl_certificate_mismatch">SSL Certificate Mismatch</string>
+ <string name="current_ssl">Current SSL</string>
+ <string name="pinned_ssl">Pinned SSL</string>
+
<!-- MainWebViewActivity Navigation Drawer. -->
<string name="navigation_drawer">Navigation Drawer</string>
<string name="navigation">Navigation</string>
<item>Images enabled</item>
<item>Images disabled</item>
</string-array>
+ <string name="pinned_ssl_certificate">Pinned SSL certificate</string>
+ <string name="saved_ssl_certificate">Saved SSL certificate</string>
+ <string name="current_website_ssl_certificate">Current website SSL certificate</string>
+ <string name="load_an_encrypted_website">Load an encrypted website before opening Domain Settings to populate the current website SSL certificate.</string>
<!-- Guide. -->
<string name="privacy_browser_guide">Privacy Browser Guide</string>
<item name="progressTintColor">@color/blue_700</item>
<item name="navigationIconTintColor">@color/blue_800</item>
<item name="findOnPageIconTintColor">@color/blue_800</item>
+ <item name="sslHeader">@color/blue_700</item>
<item name="sslTitle">@color/blue_900</item>
<item name="urlHistoryText">@color/black</item>
<item name="redText">@color/red_a700</item>
+ <item name="dialogTabLayoutTheme">@style/PrivacyBrowserTabLayoutDialogLight</item>
</style>
<!-- `windowActionModeOverlay` makes the contextual app bar cover the support app bar. `colorPrimaryDark` goes behind the status bar, which is then darkened by the overlay.-->
<item name="tabIndicatorColor">@color/white</item>
</style>
+ <style name="PrivacyBrowserTabLayoutDialogLight" parent="Widget.Design.TabLayout" >
+ <item name="android:textColorPrimary">@color/blue_700</item>
+ <item name="android:textColorSecondary">@color/blue_700_50</item>
+ </style>
+
<style name="PrivacyBrowserAlertDialogLight" parent="Theme.AppCompat.Light.Dialog.Alert" >
<item name="colorAccent">@color/blue_700</item>
</style>
<item name="progressTintColor">@color/blue_600</item>
<item name="navigationIconTintColor">@color/blue_600</item>
<item name="findOnPageIconTintColor">@color/blue_600</item>
+ <item name="sslHeader">@color/blue_400</item>
<item name="sslTitle">@color/blue_700</item>
<item name="urlHistoryText">@color/gray_200</item>
<item name="redText">@color/red_900</item>