]> gitweb.stoutner.com Git - PrivacyBrowserAndroid.git/blobdiff - app/src/main/java/com/stoutner/privacybrowser/dialogs/PinnedMismatchDialog.kt
First wrong button text in View Headers in night theme. https://redmine.stoutner...
[PrivacyBrowserAndroid.git] / app / src / main / java / com / stoutner / privacybrowser / dialogs / PinnedMismatchDialog.kt
index 0dd2ce57a9b82f8ba43b4c9aaf66fcff841bb907..c345fc5c7deffb77dcb8b432abf2cf60bbe4a93d 100644 (file)
@@ -1,36 +1,31 @@
 /*
- * Copyright © 2017-2021 Soren Stoutner <soren@stoutner.com>.
+ * Copyright 2017-2023 Soren Stoutner <soren@stoutner.com>.
  *
- * This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
+ * This file is part of Privacy Browser Android <https://www.stoutner.com/privacy-browser-android>.
  *
- * Privacy Browser is free software: you can redistribute it and/or modify
+ * Privacy Browser Android 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,
+ * Privacy Browser Android 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/>.
+ * along with Privacy Browser Android.  If not, see <http://www.gnu.org/licenses/>.
  */
 
 package com.stoutner.privacybrowser.dialogs
 
-import android.annotation.SuppressLint
 import android.app.Dialog
 import android.content.Context
 import android.content.DialogInterface
-import android.content.res.Configuration
-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
@@ -43,29 +38,11 @@ import com.stoutner.privacybrowser.adapters.PinnedMismatchPagerAdapter
 import com.stoutner.privacybrowser.helpers.DomainsDatabaseHelper
 import com.stoutner.privacybrowser.views.NestedScrollWebView
 
-// Declare the class constants.
+// Define the class constants.
 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()
@@ -84,151 +61,149 @@ class PinnedMismatchDialog : DialogFragment() {
         }
     }
 
-    // `@SuppressLint("InflateParams")` removes the warning about using `null` as the parent view group when inflating the alert dialog.
-    @SuppressLint("InflateParams")
-    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
-        // Get the WebView fragment ID.
-        val webViewFragmentId = requireArguments().getLong(WEBVIEW_FRAGMENT_ID)
-
-        // Get the current position of this WebView fragment.
-        val webViewPosition = MainWebViewActivity.webViewPagerAdapter.getPositionForId(webViewFragmentId)
-
-        // Get the WebView tab fragment.
-        val webViewTabFragment = MainWebViewActivity.webViewPagerAdapter.getPageFragment(webViewPosition)
+    // Declare the class variables.
+    private lateinit var pinnedMismatchListener: PinnedMismatchListener
 
-        // Get the fragment view.
-        val fragmentView = webViewTabFragment.requireView()
+    // The public interface is used to send information back to the parent activity.
+    interface PinnedMismatchListener {
+        fun pinnedErrorGoBack()
+    }
 
-        // Get a handle for the current WebView.
-        val nestedScrollWebView = fragmentView.findViewById<NestedScrollWebView>(R.id.nestedscroll_webview)!!
+    override fun onAttach(context: Context) {
+        // Run the default commands.
+        super.onAttach(context)
 
-        // Use an alert dialog builder to create the alert dialog.
-        val dialogBuilder = AlertDialog.Builder(requireContext(), R.style.PrivacyBrowserAlertDialog)
+        // Get a handle for the listener from the launching context.
+        pinnedMismatchListener = context as PinnedMismatchListener
+    }
 
-        // Get the favorite icon.
-        val favoriteIconBitmap = nestedScrollWebView.favoriteOrDefaultIcon
+    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)
 
-        // Get the default favorite icon drawable.  `ContextCompat` must be used until API >= 21.
-        val defaultFavoriteIconDrawable = ContextCompat.getDrawable(requireContext(), R.drawable.world)
+            // Get the current position of this WebView fragment.
+            val webViewPosition = MainWebViewActivity.webViewStateAdapter!!.getPositionForId(webViewFragmentId)
 
-        // Cast the favorite icon drawable to a bitmap drawable.
-        val defaultFavoriteIconBitmapDrawable = (defaultFavoriteIconDrawable as BitmapDrawable)
+            // Get the WebView tab fragment.
+            val webViewTabFragment = MainWebViewActivity.webViewStateAdapter!!.getPageFragment(webViewPosition)
 
-        // Store the default icon bitmap.
-        val defaultFavoriteIconBitmap = defaultFavoriteIconBitmapDrawable.bitmap
+            // Get the fragment view.
+            val fragmentView = webViewTabFragment.requireView()
 
-        // Set the favorite icon as the dialog icon if it exists.
-        if (favoriteIconBitmap.sameAs(defaultFavoriteIconBitmap)) {  // There is no website favorite icon.
-            // Get the current theme status.
-            val currentThemeStatus = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
+            // Get a handle for the current WebView.
+            val nestedScrollWebView = fragmentView.findViewById<NestedScrollWebView>(R.id.nestedscroll_webview)!!
 
-            // Set the icon according to the theme.
-            if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) {
-                dialogBuilder.setIcon(R.drawable.ssl_certificate_enabled_day)
-            } else {
-                dialogBuilder.setIcon(R.drawable.ssl_certificate_enabled_night)
-            }
-        } else {  // There is a favorite icon.
-            // Create a drawable version of the favorite icon.
-            val favoriteIconDrawable: Drawable = BitmapDrawable(resources, favoriteIconBitmap)
+            // Use an alert dialog builder to create the alert dialog.
+            val dialogBuilder = AlertDialog.Builder(requireContext(), R.style.PrivacyBrowserAlertDialog)
 
             // Set the icon.
-            dialogBuilder.setIcon(favoriteIconDrawable)
-        }
+            dialogBuilder.setIcon(R.drawable.ssl_certificate)
 
-        // Set the title.
-        dialogBuilder.setTitle(R.string.pinned_mismatch)
+            // Set the title.
+            dialogBuilder.setTitle(R.string.pinned_mismatch)
 
-        // Set the layout.  The parent view is `null` because it will be assigned by the alert dialog.
-        dialogBuilder.setView(requireActivity().layoutInflater.inflate(R.layout.pinned_mismatch_linearlayout, null))
+            // 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.  The `0` specifies the database version, but that is ignored and set instead using a constant in the domains database helper.
-            val domainsDatabaseHelper = DomainsDatabaseHelper(context, null, null, 0)
+                // 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.hasPinnedIpAddresses()) {
-                // 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.setIgnorePinnedDomainInformation(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(context)
+            // 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<ViewPager>(R.id.pinned_ssl_certificate_mismatch_viewpager)!!
+            val tabLayout = alertDialog.findViewById<TabLayout>(R.id.pinned_ssl_certificate_mismatch_tablayout)!!
 
-        //  Get handles for the views.
-        val viewPager = alertDialog.findViewById<ViewPager>(R.id.pinned_ssl_certificate_mismatch_viewpager)!!
-        val tabLayout = alertDialog.findViewById<TabLayout>(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()
+        }
     }
-}
\ No newline at end of file
+}