]> gitweb.stoutner.com Git - PrivacyBrowserAndroid.git/commitdiff
Fix a crash when restarting if the pinned mismatch dialog is displayed. https:/...
authorSoren Stoutner <soren@stoutner.com>
Wed, 17 May 2023 17:19:12 +0000 (10:19 -0700)
committerSoren Stoutner <soren@stoutner.com>
Wed, 17 May 2023 17:19:12 +0000 (10:19 -0700)
app/src/main/java/com/stoutner/privacybrowser/dialogs/PinnedMismatchDialog.kt

index 1a0ad7e3b03155e35364cb88862285c34da6bf4f..a7ac25397c4933cebb50cc387aad1726676cade5 100644 (file)
@@ -81,141 +81,153 @@ class PinnedMismatchDialog : DialogFragment() {
     }
 
     override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
-        // Get the WebView fragment ID.
-        val webViewFragmentId = requireArguments().getLong(WEBVIEW_FRAGMENT_ID)
+        // 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 current position of this WebView fragment.
-        val webViewPosition = MainWebViewActivity.webViewStateAdapter!!.getPositionForId(webViewFragmentId)
+            // Get the current position of this WebView fragment.
+            val webViewPosition = MainWebViewActivity.webViewStateAdapter!!.getPositionForId(webViewFragmentId)
 
-        // Get the WebView tab fragment.
-        val webViewTabFragment = MainWebViewActivity.webViewStateAdapter!!.getPageFragment(webViewPosition)
+            // Get the WebView tab fragment.
+            val webViewTabFragment = MainWebViewActivity.webViewStateAdapter!!.getPageFragment(webViewPosition)
 
-        // Get the fragment view.
-        val fragmentView = webViewTabFragment.requireView()
+            // Get the fragment view.
+            val fragmentView = webViewTabFragment.requireView()
 
-        // Get a handle for the current WebView.
-        val nestedScrollWebView = fragmentView.findViewById<NestedScrollWebView>(R.id.nestedscroll_webview)!!
+            // Get a handle for the current WebView.
+            val nestedScrollWebView = fragmentView.findViewById<NestedScrollWebView>(R.id.nestedscroll_webview)!!
 
-        // Use an alert dialog builder to create the alert dialog.
-        val dialogBuilder = AlertDialog.Builder(requireContext(), R.style.PrivacyBrowserAlertDialog)
+            // Use an alert dialog builder to create the alert dialog.
+            val dialogBuilder = AlertDialog.Builder(requireContext(), R.style.PrivacyBrowserAlertDialog)
 
-        // Get the favorite icon.
-        val favoriteIconBitmap = nestedScrollWebView.getFavoriteIcon()
+            // Get the favorite icon.
+            val favoriteIconBitmap = nestedScrollWebView.getFavoriteIcon()
 
-        // Get the default favorite icon drawable.  `ContextCompat` must be used until API >= 21.
-        val defaultFavoriteIconDrawable = ContextCompat.getDrawable(requireContext(), R.drawable.world)
+            // Get the default favorite icon drawable.  `ContextCompat` must be used until API >= 21.
+            val defaultFavoriteIconDrawable = ContextCompat.getDrawable(requireContext(), R.drawable.world)
 
-        // Cast the favorite icon drawable to a bitmap drawable.
-        val defaultFavoriteIconBitmapDrawable = (defaultFavoriteIconDrawable as BitmapDrawable)
+            // Cast the favorite icon drawable to a bitmap drawable.
+            val defaultFavoriteIconBitmapDrawable = (defaultFavoriteIconDrawable as BitmapDrawable)
 
-        // Store the default icon bitmap.
-        val defaultFavoriteIconBitmap = defaultFavoriteIconBitmapDrawable.bitmap
+            // Store the default icon bitmap.
+            val defaultFavoriteIconBitmap = defaultFavoriteIconBitmapDrawable.bitmap
 
-        // 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 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 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<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
+            // 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()
+
+            // 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()
+        }
     }
 }