X-Git-Url: https://gitweb.stoutner.com/?p=PrivacyBrowserAndroid.git;a=blobdiff_plain;f=app%2Fsrc%2Fmain%2Fjava%2Fcom%2Fstoutner%2Fprivacybrowser%2Fdialogs%2FPinnedMismatchDialog.kt;h=56ec5192a2d4c35cb26b4e4075b8be6c122a6eda;hp=97cd63d0ce9886595d2f342ac08a4c1f0b84852b;hb=HEAD;hpb=851453e788404e4275809f34f199d0c3023ca4ea diff --git a/app/src/main/java/com/stoutner/privacybrowser/dialogs/PinnedMismatchDialog.kt b/app/src/main/java/com/stoutner/privacybrowser/dialogs/PinnedMismatchDialog.kt index 97cd63d0..c345fc5c 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/dialogs/PinnedMismatchDialog.kt +++ b/app/src/main/java/com/stoutner/privacybrowser/dialogs/PinnedMismatchDialog.kt @@ -1,5 +1,5 @@ /* - * Copyright 2017-2022 Soren Stoutner . + * Copyright 2017-2023 Soren Stoutner . * * This file is part of Privacy Browser Android . * @@ -22,13 +22,10 @@ package com.stoutner.privacybrowser.dialogs import android.app.Dialog import android.content.Context import android.content.DialogInterface -import android.graphics.drawable.BitmapDrawable -import android.graphics.drawable.Drawable import android.os.Bundle import android.view.WindowManager import androidx.appcompat.app.AlertDialog -import androidx.core.content.ContextCompat import androidx.fragment.app.DialogFragment import androidx.preference.PreferenceManager import androidx.viewpager.widget.ViewPager @@ -45,25 +42,7 @@ import com.stoutner.privacybrowser.views.NestedScrollWebView private const val WEBVIEW_FRAGMENT_ID = "webview_fragment_id" class PinnedMismatchDialog : DialogFragment() { - // Declare the class variables. - private lateinit var pinnedMismatchListener: PinnedMismatchListener - - // The public interface is used to send information back to the parent activity. - interface PinnedMismatchListener { - fun pinnedErrorGoBack() - } - - override fun onAttach(context: Context) { - // Run the default commands. - super.onAttach(context) - - // Get a handle for the listener from the launching context. - pinnedMismatchListener = context as PinnedMismatchListener - } - companion object { - // `@JvmStatic` will no longer be required once all the code has transitioned to Kotlin. Also, the function can then be moved out of a companion object and just become a package-level function. - @JvmStatic fun displayDialog(webViewFragmentId: Long): PinnedMismatchDialog { // Create an arguments bundle. val argumentsBundle = Bundle() @@ -82,142 +61,149 @@ class PinnedMismatchDialog : DialogFragment() { } } - override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { - // Get the WebView fragment ID. - val webViewFragmentId = requireArguments().getLong(WEBVIEW_FRAGMENT_ID) + // Declare the class variables. + private lateinit var pinnedMismatchListener: PinnedMismatchListener - // Get the current position of this WebView fragment. - val webViewPosition = MainWebViewActivity.webViewPagerAdapter.getPositionForId(webViewFragmentId) + // The public interface is used to send information back to the parent activity. + interface PinnedMismatchListener { + fun pinnedErrorGoBack() + } - // Get the WebView tab fragment. - val webViewTabFragment = MainWebViewActivity.webViewPagerAdapter.getPageFragment(webViewPosition) + override fun onAttach(context: Context) { + // Run the default commands. + super.onAttach(context) - // Get the fragment view. - val fragmentView = webViewTabFragment.requireView() + // Get a handle for the listener from the launching context. + pinnedMismatchListener = context as PinnedMismatchListener + } - // Get a handle for the current WebView. - val nestedScrollWebView = fragmentView.findViewById(R.id.nestedscroll_webview)!! + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + // Try to create the dialog. This will fail if the app was restarted while the dialog is shown because the WebView view pager will not have been populated yet. + try { + // Get the WebView fragment ID. + val webViewFragmentId = requireArguments().getLong(WEBVIEW_FRAGMENT_ID) - // Use an alert dialog builder to create the alert dialog. - val dialogBuilder = AlertDialog.Builder(requireContext(), R.style.PrivacyBrowserAlertDialog) + // Get the current position of this WebView fragment. + val webViewPosition = MainWebViewActivity.webViewStateAdapter!!.getPositionForId(webViewFragmentId) - // Get the favorite icon. - val favoriteIconBitmap = nestedScrollWebView.getFavoriteIcon() + // Get the WebView tab fragment. + val webViewTabFragment = MainWebViewActivity.webViewStateAdapter!!.getPageFragment(webViewPosition) - // Get the default favorite icon drawable. `ContextCompat` must be used until API >= 21. - val defaultFavoriteIconDrawable = ContextCompat.getDrawable(requireContext(), R.drawable.world) + // Get the fragment view. + val fragmentView = webViewTabFragment.requireView() - // Cast the favorite icon drawable to a bitmap drawable. - val defaultFavoriteIconBitmapDrawable = (defaultFavoriteIconDrawable as BitmapDrawable) + // Get a handle for the current WebView. + val nestedScrollWebView = fragmentView.findViewById(R.id.nestedscroll_webview)!! - // Store the default icon bitmap. - val defaultFavoriteIconBitmap = defaultFavoriteIconBitmapDrawable.bitmap + // Use an alert dialog builder to create the alert dialog. + val dialogBuilder = AlertDialog.Builder(requireContext(), R.style.PrivacyBrowserAlertDialog) - // Set the favorite icon as the dialog icon if it exists. - if (favoriteIconBitmap.sameAs(defaultFavoriteIconBitmap)) { // There is no website favorite icon. // Set the icon. dialogBuilder.setIcon(R.drawable.ssl_certificate) - } else { // There is a favorite icon. - // Create a drawable version of the favorite icon. - val favoriteIconDrawable: Drawable = BitmapDrawable(resources, favoriteIconBitmap) - - // Set the icon. - dialogBuilder.setIcon(favoriteIconDrawable) - } - // Set the title. - dialogBuilder.setTitle(R.string.pinned_mismatch) + // Set the title. + dialogBuilder.setTitle(R.string.pinned_mismatch) - // Set the layout. - dialogBuilder.setView(R.layout.pinned_mismatch_linearlayout) + // Set the layout. + dialogBuilder.setView(R.layout.pinned_mismatch_linearlayout) - // Set the update button listener. - dialogBuilder.setNeutralButton(R.string.update) { _: DialogInterface?, _: Int -> - // Get the current SSL certificate. - val currentSslCertificate = nestedScrollWebView.certificate!! + // Set the update button listener. + dialogBuilder.setNeutralButton(R.string.update) { _: DialogInterface?, _: Int -> + // Get the current SSL certificate. + val currentSslCertificate = nestedScrollWebView.certificate!! - // Get the dates from the certificate. - val currentSslStartDate = currentSslCertificate.validNotBeforeDate - val currentSslEndDate = currentSslCertificate.validNotAfterDate + // Get the dates from the certificate. + val currentSslStartDate = currentSslCertificate.validNotBeforeDate + val currentSslEndDate = currentSslCertificate.validNotAfterDate - // Convert the dates into longs. If the date is null, a long value of `0` will be stored in the domains database entry. - val currentSslStartDateLong: Long = currentSslStartDate?.time ?: 0 - val currentSslEndDateLong: Long = currentSslEndDate?.time ?: 0 + // Convert the dates into longs. If the date is null, a long value of `0` will be stored in the domains database entry. + val currentSslStartDateLong: Long = currentSslStartDate?.time ?: 0 + val currentSslEndDateLong: Long = currentSslEndDate?.time ?: 0 - // Initialize the database handler. - val domainsDatabaseHelper = DomainsDatabaseHelper(requireContext()) + // Initialize the database handler. + val domainsDatabaseHelper = DomainsDatabaseHelper(requireContext()) - // Update the SSL certificate if it is pinned. - if (nestedScrollWebView.hasPinnedSslCertificate()) { - // Update the pinned SSL certificate in the domain database. - domainsDatabaseHelper.updatePinnedSslCertificate(nestedScrollWebView.domainSettingsDatabaseId, currentSslCertificate.issuedTo.cName, currentSslCertificate.issuedTo.oName, + // Update the SSL certificate if it is pinned. + if (nestedScrollWebView.hasPinnedSslCertificate()) { + // Update the pinned SSL certificate in the domain database. + domainsDatabaseHelper.updatePinnedSslCertificate(nestedScrollWebView.domainSettingsDatabaseId, currentSslCertificate.issuedTo.cName, currentSslCertificate.issuedTo.oName, currentSslCertificate.issuedTo.uName, currentSslCertificate.issuedBy.cName, currentSslCertificate.issuedBy.oName, currentSslCertificate.issuedBy.uName, currentSslStartDateLong, currentSslEndDateLong) - // Update the pinned SSL certificate in the nested scroll WebView. - nestedScrollWebView.setPinnedSslCertificate(currentSslCertificate.issuedTo.cName, currentSslCertificate.issuedTo.oName, currentSslCertificate.issuedTo.uName, + // Update the pinned SSL certificate in the nested scroll WebView. + nestedScrollWebView.setPinnedSslCertificate(currentSslCertificate.issuedTo.cName, currentSslCertificate.issuedTo.oName, currentSslCertificate.issuedTo.uName, currentSslCertificate.issuedBy.cName, currentSslCertificate.issuedBy.oName, currentSslCertificate.issuedBy.uName, currentSslStartDate, currentSslEndDate) - } + } - // Update the IP addresses if they are pinned. - if (nestedScrollWebView.pinnedIpAddresses != "") { - // Update the pinned IP addresses in the domain database. - domainsDatabaseHelper.updatePinnedIpAddresses(nestedScrollWebView.domainSettingsDatabaseId, nestedScrollWebView. currentIpAddresses) + // Update the IP addresses if they are pinned. + if (nestedScrollWebView.pinnedIpAddresses != "") { + // Update the pinned IP addresses in the domain database. + domainsDatabaseHelper.updatePinnedIpAddresses(nestedScrollWebView.domainSettingsDatabaseId, nestedScrollWebView.currentIpAddresses) - // Update the pinned IP addresses in the nested scroll WebView. - nestedScrollWebView.pinnedIpAddresses = nestedScrollWebView.currentIpAddresses + // Update the pinned IP addresses in the nested scroll WebView. + nestedScrollWebView.pinnedIpAddresses = nestedScrollWebView.currentIpAddresses + } } - } - // Set the back button listener. - dialogBuilder.setNegativeButton(R.string.back) { _: DialogInterface?, _: Int -> - if (nestedScrollWebView.canGoBack()) { // There is a back page in the history. - // Invoke the navigate history listener in the calling activity. These commands cannot be run here because they need access to `applyDomainSettings()`. - pinnedMismatchListener.pinnedErrorGoBack() - } else { // There are no pages to go back to. - // Load a blank page - nestedScrollWebView.loadUrl("") + // Set the back button listener. + dialogBuilder.setNegativeButton(R.string.back) { _: DialogInterface?, _: Int -> + if (nestedScrollWebView.canGoBack()) { // There is a back page in the history. + // Invoke the navigate history listener in the calling activity. These commands cannot be run here because they need access to `applyDomainSettings()`. + pinnedMismatchListener.pinnedErrorGoBack() + } else { // There are no pages to go back to. + // Load a blank page + nestedScrollWebView.loadUrl("") + } } - } - // Set the proceed button listener. - dialogBuilder.setPositiveButton(R.string.proceed) { _: DialogInterface?, _: Int -> - // Do not check the pinned information for this domain again until the domain changes. - nestedScrollWebView.ignorePinnedDomainInformation = true - } + // Set the proceed button listener. + dialogBuilder.setPositiveButton(R.string.proceed) { _: DialogInterface?, _: Int -> + // Do not check the pinned information for this domain again until the domain changes. + nestedScrollWebView.ignorePinnedDomainInformation = true + } - // Create an alert dialog from the alert dialog builder. - val alertDialog = dialogBuilder.create() + // Create an alert dialog from the alert dialog builder. + val alertDialog = dialogBuilder.create() - // Get a handle for the shared preferences. - val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(requireContext()) + // Get a handle for the shared preferences. + val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(requireContext()) - // Get the screenshot preference. - val allowScreenshots = sharedPreferences.getBoolean(getString(R.string.allow_screenshots_key), false) + // Get the screenshot preference. + val allowScreenshots = sharedPreferences.getBoolean(getString(R.string.allow_screenshots_key), false) - // Disable screenshots if not allowed. - if (!allowScreenshots) { - // Disable screenshots. - alertDialog.window!!.addFlags(WindowManager.LayoutParams.FLAG_SECURE) - } + // Disable screenshots if not allowed. + if (!allowScreenshots) { + // Disable screenshots. + alertDialog.window!!.addFlags(WindowManager.LayoutParams.FLAG_SECURE) + } + + // The alert dialog must be shown before items in the layout can be modified. + alertDialog.show() - // The alert dialog must be shown before items in the layout can be modified. - alertDialog.show() + // Get handles for the views. + val viewPager = alertDialog.findViewById(R.id.pinned_ssl_certificate_mismatch_viewpager)!! + val tabLayout = alertDialog.findViewById(R.id.pinned_ssl_certificate_mismatch_tablayout)!! - // Get handles for the views. - val viewPager = alertDialog.findViewById(R.id.pinned_ssl_certificate_mismatch_viewpager)!! - val tabLayout = alertDialog.findViewById(R.id.pinned_ssl_certificate_mismatch_tablayout)!! + // Initialize the pinned mismatch pager adapter. + val pinnedMismatchPagerAdapter = PinnedMismatchPagerAdapter(requireContext(), layoutInflater, webViewFragmentId) - // Initialize the pinned mismatch pager adapter. - val pinnedMismatchPagerAdapter = PinnedMismatchPagerAdapter(requireContext(), layoutInflater, webViewFragmentId) + // Set the view pager adapter. + viewPager.adapter = pinnedMismatchPagerAdapter - // Set the view pager adapter. - viewPager.adapter = pinnedMismatchPagerAdapter + // Connect the tab layout to the view pager. + tabLayout.setupWithViewPager(viewPager) - // Connect the tab layout to the view pager. - tabLayout.setupWithViewPager(viewPager) + // Return the alert dialog. + return alertDialog + } catch (exception: Exception) { // The app was restarted while the dialog was displayed. + // Dismiss this new instance of the dialog. Amazingly, the old instance will be restored by Android and, even more amazingly, will be fully functional. + dismiss() - // Return the alert dialog. - return alertDialog + // Use an alert dialog builder to create an empty alert dialog. + val dialogBuilder = AlertDialog.Builder(requireContext(), R.style.PrivacyBrowserAlertDialog) + + // Return the empty alert dialog. + return dialogBuilder.create() + } } }