]> gitweb.stoutner.com Git - PrivacyBrowserAndroid.git/blobdiff - app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.java
Update the file name when the URL changes in SaveDialog. https://redmine.stoutner...
[PrivacyBrowserAndroid.git] / app / src / main / java / com / stoutner / privacybrowser / activities / MainWebViewActivity.java
index 2f41688a5a56f349988b666f98887b4a24379965..d3e352b60834ac5b0b9dcd3e3f66fe6051d4e938 100644 (file)
@@ -46,7 +46,6 @@ import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.net.http.SslCertificate;
 import android.net.http.SslError;
-import android.os.AsyncTask;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.Environment;
@@ -99,6 +98,7 @@ import android.widget.RelativeLayout;
 import android.widget.TextView;
 
 import androidx.activity.OnBackPressedCallback;
+import androidx.activity.result.ActivityResult;
 import androidx.activity.result.ActivityResultCallback;
 import androidx.activity.result.ActivityResultLauncher;
 import androidx.activity.result.contract.ActivityResultContracts;
@@ -128,12 +128,12 @@ import com.google.android.material.tabs.TabLayout;
 
 import com.stoutner.privacybrowser.R;
 import com.stoutner.privacybrowser.adapters.WebViewPagerAdapter;
-import com.stoutner.privacybrowser.asynctasks.GetHostIpAddresses;
-import com.stoutner.privacybrowser.asynctasks.PopulateBlocklists;
-import com.stoutner.privacybrowser.asynctasks.PrepareSaveDialog;
 import com.stoutner.privacybrowser.asynctasks.SaveUrl;
 import com.stoutner.privacybrowser.asynctasks.SaveWebpageImage;
-import com.stoutner.privacybrowser.dataclasses.PendingDialog;
+import com.stoutner.privacybrowser.coroutines.GetHostIpAddressesCoroutine;
+import com.stoutner.privacybrowser.coroutines.PopulateBlocklistsCoroutine;
+import com.stoutner.privacybrowser.coroutines.PrepareSaveDialogCoroutine;
+import com.stoutner.privacybrowser.dataclasses.PendingDialogDataClass;
 import com.stoutner.privacybrowser.dialogs.CreateBookmarkDialog;
 import com.stoutner.privacybrowser.dialogs.CreateBookmarkFolderDialog;
 import com.stoutner.privacybrowser.dialogs.CreateHomeScreenShortcutDialog;
@@ -153,6 +153,7 @@ import com.stoutner.privacybrowser.helpers.BookmarksDatabaseHelper;
 import com.stoutner.privacybrowser.helpers.DomainsDatabaseHelper;
 import com.stoutner.privacybrowser.helpers.ProxyHelper;
 import com.stoutner.privacybrowser.helpers.SanitizeUrlHelper;
+import com.stoutner.privacybrowser.helpers.UrlHelper;
 import com.stoutner.privacybrowser.views.NestedScrollWebView;
 
 import java.io.ByteArrayInputStream;
@@ -185,12 +186,12 @@ import kotlin.Pair;
 
 public class MainWebViewActivity extends AppCompatActivity implements CreateBookmarkDialog.CreateBookmarkListener, CreateBookmarkFolderDialog.CreateBookmarkFolderListener,
         FontSizeDialog.UpdateFontSizeListener, NavigationView.OnNavigationItemSelectedListener, OpenDialog.OpenListener, PinnedMismatchDialog.PinnedMismatchListener,
-        PopulateBlocklists.PopulateBlocklistsListener, SaveDialog.SaveListener, UrlHistoryDialog.NavigateHistoryListener, WebViewTabFragment.NewTabListener {
+        PopulateBlocklistsCoroutine.PopulateBlocklistsListener, SaveDialog.SaveListener, UrlHistoryDialog.NavigateHistoryListener, WebViewTabFragment.NewTabListener {
 
     // Define the public static variables.
     public static final ExecutorService executorService = Executors.newFixedThreadPool(4);
     public static String orbotStatus = "unknown";
-    public static final ArrayList<PendingDialog> pendingDialogsArrayList =  new ArrayList<>();
+    public static final ArrayList<PendingDialogDataClass> pendingDialogsArrayList =  new ArrayList<>();
     public static String proxyMode = ProxyHelper.NONE;
 
     // Declare the public static variables.
@@ -209,10 +210,6 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
     public final static int DOMAINS_WEBVIEW_DEFAULT_USER_AGENT = 2;
     public final static int DOMAINS_CUSTOM_USER_AGENT = 12;
 
-    // Define the start activity for result request codes.  The public static entry is accessed from `OpenDialog()`.
-    private final int BROWSE_FILE_UPLOAD_REQUEST_CODE = 0;
-    public final static int BROWSE_OPEN_REQUEST_CODE = 1;
-
     // Define the saved instance state constants.
     private final String BOOKMARKS_DRAWER_PINNED = "bookmarks_drawer_pinned";
     private final String PROXY_MODE = "proxy_mode";
@@ -226,10 +223,6 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
     private int savedTabPosition;
     private String savedProxyMode;
 
-    // Define the class variables.
-    @SuppressWarnings("rawtypes")
-    AsyncTask populateBlocklists;
-
     // The current WebView is used in `onCreate()`, `onPrepareOptionsMenu()`, `onOptionsItemSelected()`, `onNavigationItemSelected()`, `onRestart()`, `onCreateContextMenu()`, `findPreviousOnPage()`,
     // `findNextOnPage()`, `closeFindOnPage()`, `loadUrlFromTextBox()`, `onSslMismatchBack()`, `applyProxy()`, and `applyDomainSettings()`.
     private NestedScrollWebView currentWebView;
@@ -271,7 +264,6 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
     private BookmarksDatabaseHelper bookmarksDatabaseHelper;
     private DomainsDatabaseHelper domainsDatabaseHelper;
     private ProxyHelper proxyHelper;
-    private SanitizeUrlHelper sanitizeUrlHelper;
 
     // Declare the class variables
     private boolean bookmarksDrawerPinned;
@@ -473,6 +465,16 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
                 }
             });
 
+    // Define the save webpage image activity result launcher.  It must be defined before `onCreate()` is run or the app will crash.
+    private final ActivityResultLauncher<Intent> browseFileUploadActivityResultLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(),
+            new ActivityResultCallback<ActivityResult>() {
+                @Override
+                public void onActivityResult(ActivityResult activityResult) {
+                    // Pass the file to the WebView.
+                    fileChooserCallback.onReceiveValue(WebChromeClient.FileChooserParams.parseResult(activityResult.getResultCode(), activityResult.getData()));
+                }
+            });
+
     // Remove the warning about needing to override `performClick()` when using an `OnTouchListener` with WebView.
     @SuppressLint("ClickableViewAccessibility")
     @Override
@@ -606,7 +608,6 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
         bookmarksDatabaseHelper = new BookmarksDatabaseHelper(this);
         domainsDatabaseHelper = new DomainsDatabaseHelper(this);
         proxyHelper = new ProxyHelper();
-        sanitizeUrlHelper = new SanitizeUrlHelper();
 
         // Update the bookmarks drawer pinned image view.
         updateBookmarksDrawerPinnedImageView();
@@ -631,7 +632,8 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
                 } else if (displayingFullScreenVideo) {  // A full screen video is shown.
                     // Exit the full screen video.
                     exitFullScreenVideo();
-                } else if (currentWebView.canGoBack()) {  // There is at least one item in the current WebView history.
+                    // It shouldn't be possible for the currentWebView to be null, but crash logs indicate it sometimes happens.
+                } else if ((currentWebView != null) && (currentWebView.canGoBack())) {  // There is at least one item in the current WebView history.
                     // Get the current web back forward list.
                     WebBackForwardList webBackForwardList = currentWebView.copyBackForwardList();
 
@@ -656,8 +658,11 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
         // Register the on back pressed callback.
         getOnBackPressedDispatcher().addCallback(this, onBackPressedCallback);
 
+        // Instantiate the populate blocklists coroutine.
+        PopulateBlocklistsCoroutine populateBlocklistsCoroutine = new PopulateBlocklistsCoroutine(this);
+
         // Populate the blocklists.
-        populateBlocklists = new PopulateBlocklists(this, this).execute();
+        populateBlocklistsCoroutine.populateBlocklists(this);
     }
 
     @Override
@@ -850,10 +855,10 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
         // Show any pending dialogs.
         for (int i = 0; i < pendingDialogsArrayList.size(); i++) {
             // Get the pending dialog from the array list.
-            PendingDialog pendingDialog = pendingDialogsArrayList.get(i);
+            PendingDialogDataClass pendingDialogDataClass = pendingDialogsArrayList.get(i);
 
             // Show the pending dialog.
-            pendingDialog.dialogFragment.show(getSupportFragmentManager(), pendingDialog.tag);
+            pendingDialogDataClass.dialogFragment.show(getSupportFragmentManager(), pendingDialogDataClass.tag);
         }
 
         // Clear the pending dialogs array list.
@@ -951,11 +956,6 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
             bookmarksDatabaseHelper.close();
         }
 
-        // Stop populating the blocklists if the AsyncTask is running in the background.
-        if (populateBlocklists != null) {
-            populateBlocklists.cancel(true);
-        }
-
         // Run the default commands.
         super.onDestroy();
     }
@@ -1848,8 +1848,8 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
                 downloadUrlWithExternalApp(currentWebView.getCurrentUrl());
             } else {  // Handle the download inside of Privacy Browser.
                 // Prepare the save dialog.  The dialog will be displayed once the file size and the content disposition have been acquired.
-                new PrepareSaveDialog(this, this, getSupportFragmentManager(), currentWebView.getSettings().getUserAgentString(),
-                        currentWebView.getAcceptCookies()).execute(currentWebView.getCurrentUrl());
+                PrepareSaveDialogCoroutine.prepareSaveDialog(this, getSupportFragmentManager(), currentWebView.getCurrentUrl(), currentWebView.getSettings().getUserAgentString(),
+                        currentWebView.getAcceptCookies());
             }
 
             // Consume the event.
@@ -1869,7 +1869,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
         } else if (menuItemId == R.id.add_to_homescreen) {  // Add to homescreen.
             // Instantiate the create home screen shortcut dialog.
             DialogFragment createHomeScreenShortcutDialogFragment = CreateHomeScreenShortcutDialog.createDialog(currentWebView.getTitle(), currentWebView.getUrl(),
-                    currentWebView.getFavoriteOrDefaultIcon());
+                    currentWebView.getFavoriteIcon());
 
             // Show the create home screen shortcut dialog.
             createHomeScreenShortcutDialogFragment.show(getSupportFragmentManager(), getString(R.string.create_shortcut));
@@ -2345,8 +2345,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
                         downloadUrlWithExternalApp(linkUrl);
                     } else {  // Handle the download inside of Privacy Browser.
                         // Prepare the save dialog.  The dialog will be displayed once the file size and the content disposition have been acquired.
-                        new PrepareSaveDialog(this, this, getSupportFragmentManager(), currentWebView.getSettings().getUserAgentString(),
-                                currentWebView.getAcceptCookies()).execute(linkUrl);
+                        PrepareSaveDialogCoroutine.prepareSaveDialog(this, getSupportFragmentManager(), linkUrl, currentWebView.getSettings().getUserAgentString(), currentWebView.getAcceptCookies());
                     }
 
                     // Consume the event.
@@ -2417,8 +2416,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
                         downloadUrlWithExternalApp(imageUrl);
                     } else {  // Handle the download inside of Privacy Browser.
                         // Prepare the save dialog.  The dialog will be displayed once the file size and the content disposition have been acquired.
-                        new PrepareSaveDialog(this, this, getSupportFragmentManager(), currentWebView.getSettings().getUserAgentString(),
-                                currentWebView.getAcceptCookies()).execute(imageUrl);
+                        PrepareSaveDialogCoroutine.prepareSaveDialog(this, getSupportFragmentManager(), imageUrl, currentWebView.getSettings().getUserAgentString(), currentWebView.getAcceptCookies());
                     }
 
                     // Consume the event.
@@ -2522,8 +2520,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
                         downloadUrlWithExternalApp(imageUrl);
                     } else {  // Handle the download inside of Privacy Browser.
                         // Prepare the save dialog.  The dialog will be displayed once the file size and the content disposition have been acquired.
-                        new PrepareSaveDialog(this, this, getSupportFragmentManager(), currentWebView.getSettings().getUserAgentString(),
-                                currentWebView.getAcceptCookies()).execute(imageUrl);
+                        PrepareSaveDialogCoroutine.prepareSaveDialog(this, getSupportFragmentManager(), imageUrl, currentWebView.getSettings().getUserAgentString(), currentWebView.getAcceptCookies());
                     }
 
                     // Consume the event.
@@ -2549,8 +2546,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
                         downloadUrlWithExternalApp(linkUrl);
                     } else {  // Handle the download inside of Privacy Browser.
                         // Prepare the save dialog.  The dialog will be displayed once the file size and the content disposition have been acquired.
-                        new PrepareSaveDialog(this, this, getSupportFragmentManager(), currentWebView.getSettings().getUserAgentString(),
-                                currentWebView.getAcceptCookies()).execute(linkUrl);
+                        PrepareSaveDialogCoroutine.prepareSaveDialog(this, getSupportFragmentManager(), linkUrl, currentWebView.getSettings().getUserAgentString(), currentWebView.getAcceptCookies());
                     }
 
                     // Consume the event.
@@ -2718,53 +2714,6 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
         bookmarksListView.setSelection(0);
     }
 
-    // Process the results of a file browse.
-    @Override
-    public void onActivityResult(int requestCode, int resultCode, Intent returnedIntent) {
-        // Run the default commands.
-        super.onActivityResult(requestCode, resultCode, returnedIntent);
-
-        // Run the commands that correlate to the specified request code.
-        switch (requestCode) {
-            case BROWSE_FILE_UPLOAD_REQUEST_CODE:
-                // Pass the file to the WebView.
-                fileChooserCallback.onReceiveValue(WebChromeClient.FileChooserParams.parseResult(resultCode, returnedIntent));
-                break;
-
-            case BROWSE_OPEN_REQUEST_CODE:
-                // Don't do anything if the user pressed back from the file picker.
-                if (resultCode == Activity.RESULT_OK) {
-                    // Get a handle for the open dialog fragment.
-                    DialogFragment openDialogFragment = (DialogFragment) getSupportFragmentManager().findFragmentByTag(getString(R.string.open));
-
-                    // Only update the file name if the dialog still exists.
-                    if (openDialogFragment != null) {
-                        // Get a handle for the open dialog.
-                        Dialog openDialog = openDialogFragment.getDialog();
-
-                        // Remove the incorrect lint warning below that the dialog might be null.
-                        assert openDialog != null;
-
-                        // Get a handle for the file name edit text.
-                        EditText fileNameEditText = openDialog.findViewById(R.id.file_name_edittext);
-
-                        // Get the file name URI from the intent.
-                        Uri fileNameUri = returnedIntent.getData();
-
-                        // Get the file name string from the URI.
-                        String fileNameString = fileNameUri.toString();
-
-                        // Set the file name text.
-                        fileNameEditText.setText(fileNameString);
-
-                        // Move the cursor to the end of the file name edit text.
-                        fileNameEditText.setSelection(fileNameString.length());
-                    }
-                }
-                break;
-        }
-    }
-
     private void loadUrlFromTextBox() {
         // Get the text from urlTextBox and convert it to a string.  trim() removes white spaces from the beginning and end of the string.
         String unformattedUrlString = urlEditText.getText().toString().trim();
@@ -3174,7 +3123,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
             @Override
             public void onTabReselected(TabLayout.Tab tab) {
                 // Instantiate the View SSL Certificate dialog.
-                DialogFragment viewSslCertificateDialogFragment = ViewSslCertificateDialog.displayDialog(currentWebView.getWebViewFragmentId(), currentWebView.getFavoriteOrDefaultIcon());
+                DialogFragment viewSslCertificateDialogFragment = ViewSslCertificateDialog.displayDialog(currentWebView.getWebViewFragmentId(), currentWebView.getFavoriteIcon());
 
                 // Display the View SSL Certificate dialog.
                 viewSslCertificateDialogFragment.show(getSupportFragmentManager(), getString(R.string.view_ssl_certificate));
@@ -3190,7 +3139,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
         // Set the launch bookmarks activity FAB to launch the bookmarks activity.
         launchBookmarksActivityFab.setOnClickListener(v -> {
             // Get a copy of the favorite icon bitmap.
-            Bitmap favoriteIconBitmap = currentWebView.getFavoriteOrDefaultIcon();
+            Bitmap favoriteIconBitmap = currentWebView.getFavoriteIcon();
 
             // Create a favorite icon byte array output stream.
             ByteArrayOutputStream favoriteIconByteArrayOutputStream = new ByteArrayOutputStream();
@@ -3217,7 +3166,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
         // Set the create new bookmark folder FAB to display an alert dialog.
         createBookmarkFolderFab.setOnClickListener(v -> {
             // Create a create bookmark folder dialog.
-            DialogFragment createBookmarkFolderDialog = CreateBookmarkFolderDialog.createBookmarkFolder(currentWebView.getFavoriteOrDefaultIcon());
+            DialogFragment createBookmarkFolderDialog = CreateBookmarkFolderDialog.createBookmarkFolder(currentWebView.getFavoriteIcon());
 
             // Show the create bookmark folder dialog.
             createBookmarkFolderDialog.show(getSupportFragmentManager(), getString(R.string.create_folder));
@@ -3226,7 +3175,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
         // Set the create new bookmark FAB to display an alert dialog.
         createBookmarkFab.setOnClickListener(view -> {
             // Instantiate the create bookmark dialog.
-            DialogFragment createBookmarkDialog = CreateBookmarkDialog.createBookmark(currentWebView.getUrl(), currentWebView.getTitle(), currentWebView.getFavoriteOrDefaultIcon());
+            DialogFragment createBookmarkDialog = CreateBookmarkDialog.createBookmark(currentWebView.getUrl(), currentWebView.getTitle(), currentWebView.getFavoriteIcon());
 
             // Display the create bookmark dialog.
             createBookmarkDialog.show(getSupportFragmentManager(), getString(R.string.create_bookmark));
@@ -3649,7 +3598,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
                     TextView tabTitleTextView = tabCustomView.findViewById(R.id.title_textview);
 
                     // Set the default favorite icon as the favorite icon for this tab.
-                    tabFavoriteIconImageView.setImageBitmap(Bitmap.createScaledBitmap(nestedScrollWebView.getFavoriteOrDefaultIcon(), 64, 64, true));
+                    tabFavoriteIconImageView.setImageBitmap(Bitmap.createScaledBitmap(nestedScrollWebView.getFavoriteIcon(), 64, 64, true));
 
                     // Set the loading title text.
                     tabTitleTextView.setText(R.string.loading);
@@ -4137,7 +4086,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
                                 waitingForProxyDialogFragment.show(getSupportFragmentManager(), getString(R.string.waiting_for_proxy_dialog));
                             } catch (Exception waitingForTorException) {
                                 // Add the dialog to the pending dialog array list.  It will be displayed in `onStart()`.
-                                pendingDialogsArrayList.add(new PendingDialog(waitingForProxyDialogFragment, getString(R.string.waiting_for_proxy_dialog)));
+                                pendingDialogsArrayList.add(new PendingDialogDataClass(waitingForProxyDialogFragment, getString(R.string.waiting_for_proxy_dialog)));
                             }
                         }
                     }
@@ -4153,7 +4102,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
                             orbotNotInstalledDialogFragment.show(getSupportFragmentManager(), getString(R.string.proxy_not_installed_dialog));
                         } catch (Exception orbotNotInstalledException) {
                             // Add the dialog to the pending dialog array list.  It will be displayed in `onStart()`.
-                            pendingDialogsArrayList.add(new PendingDialog(orbotNotInstalledDialogFragment, getString(R.string.proxy_not_installed_dialog)));
+                            pendingDialogsArrayList.add(new PendingDialogDataClass(orbotNotInstalledDialogFragment, getString(R.string.proxy_not_installed_dialog)));
                         }
                     }
                 }
@@ -4189,7 +4138,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
                                 i2pNotInstalledDialogFragment.show(getSupportFragmentManager(), getString(R.string.proxy_not_installed_dialog));
                             } catch (Exception i2pNotInstalledException) {
                                 // Add the dialog to the pending dialog array list.  It will be displayed in `onStart()`.
-                                pendingDialogsArrayList.add(new PendingDialog(i2pNotInstalledDialogFragment, getString(R.string.proxy_not_installed_dialog)));
+                                pendingDialogsArrayList.add(new PendingDialogDataClass(i2pNotInstalledDialogFragment, getString(R.string.proxy_not_installed_dialog)));
                             }
                         }
                     }
@@ -4421,11 +4370,11 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
     private String sanitizeUrl(String url) {
         // Sanitize tracking queries.
         if (sanitizeTrackingQueries)
-            url = sanitizeUrlHelper.sanitizeTrackingQueries(url);
+            url = SanitizeUrlHelper.sanitizeTrackingQueries(url);
 
         // Sanitize AMP redirects.
         if (sanitizeAmpRedirects)
-            url = sanitizeUrlHelper.sanitizeAmpRedirects(url);
+            url = SanitizeUrlHelper.sanitizeAmpRedirects(url);
 
         // Return the sanitized URL.
         return url;
@@ -5190,10 +5139,10 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
                 }
 
                 // Get the file name from the content disposition.
-                String fileNameString = PrepareSaveDialog.getFileNameFromHeaders(this, contentDisposition, mimetype, downloadUrl);
+                String fileNameString = UrlHelper.getFileName(this, contentDisposition, mimetype, downloadUrl);
 
                 // Instantiate the save dialog.
-                DialogFragment saveDialogFragment = SaveDialog.saveUrl(downloadUrl, formattedFileSizeString, fileNameString, userAgent,
+                DialogFragment saveDialogFragment = SaveDialog.saveUrl(downloadUrl, fileNameString, formattedFileSizeString, userAgent,
                         nestedScrollWebView.getAcceptCookies());
 
                 // Try to show the dialog.  The download listener continues to function even when the WebView is paused.  Attempting to display a dialog in that state leads to a crash.
@@ -5202,7 +5151,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
                     saveDialogFragment.show(getSupportFragmentManager(), getString(R.string.save_dialog));
                 } catch (Exception exception) {  // The dialog could not be shown.
                     // Add the dialog to the pending dialog array list.  It will be displayed in `onStart()`.
-                    pendingDialogsArrayList.add(new PendingDialog(saveDialogFragment, getString(R.string.save_dialog)));
+                    pendingDialogsArrayList.add(new PendingDialogDataClass(saveDialogFragment, getString(R.string.save_dialog)));
                 }
             }
         });
@@ -5282,10 +5231,12 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
             // Set the favorite icon when it changes.
             @Override
             public void onReceivedIcon(WebView view, Bitmap icon) {
-                // Only update the favorite icon if the website has finished loading.
-                if (progressBar.getVisibility() == View.GONE) {
+                // Only update the favorite icon if the website has finished loading and the new favorite icon height is greater than the current favorite icon height.
+                // This prevents low resolution icons from replacing high resolution one.
+                // The check for the visibility of the progress bar can possibly be removed once https://redmine.stoutner.com/issues/747 is fixed.
+                if ((progressBar.getVisibility() == View.GONE) && (icon.getHeight() > nestedScrollWebView.getFavoriteIconHeight())) {
                     // Store the new favorite icon.
-                    nestedScrollWebView.setFavoriteOrDefaultIcon(icon);
+                    nestedScrollWebView.setFavoriteIcon(icon);
 
                     // Get the current page position.
                     int currentPosition = webViewPagerAdapter.getPositionForId(nestedScrollWebView.getWebViewFragmentId());
@@ -5396,8 +5347,8 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
 
                 // Check to see if the file chooser intent resolves to an installed package.
                 if (fileChooserIntent.resolveActivity(packageManager) != null) {  // The file chooser intent is fine.
-                    // Start the file chooser intent.
-                    startActivityForResult(fileChooserIntent, BROWSE_FILE_UPLOAD_REQUEST_CODE);
+                    // Launch the file chooser intent.
+                    browseFileUploadActivityResultLauncher.launch(fileChooserIntent);
                 } else {  // The file chooser intent will cause a crash.
                     // Create a generic intent to open a chooser.
                     Intent genericFileChooserIntent = new Intent(Intent.ACTION_GET_CONTENT);
@@ -5408,8 +5359,8 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
                     // Set the file type to everything.
                     genericFileChooserIntent.setType("*/*");
 
-                    // Start the generic file chooser intent.
-                    startActivityForResult(genericFileChooserIntent, BROWSE_FILE_UPLOAD_REQUEST_CODE);
+                    // Launch the generic file chooser intent.
+                    browseFileUploadActivityResultLauncher.launch(genericFileChooserIntent);
                 }
                 return true;
             }
@@ -5911,8 +5862,13 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
                 // Get a URI for the current URL.
                 Uri currentUri = Uri.parse(url);
 
-                // Get the IP addresses for the host.
-                new GetHostIpAddresses(activity, getSupportFragmentManager(), nestedScrollWebView).execute(currentUri.getHost());
+                // Get the current domain name.
+                String currentDomainName = currentUri.getHost();
+
+                if ((currentDomainName != null) && !currentDomainName.isEmpty()) {
+                    // Get the IP addresses for the current URI.
+                    GetHostIpAddressesCoroutine.getAddresses(currentDomainName, nestedScrollWebView, getSupportFragmentManager(), getString(R.string.pinned_mismatch));
+                }
 
                 // Replace Refresh with Stop if the options menu has been created.  (The first WebView typically begins loading before the menu items are instantiated.)
                 if (optionsMenu != null) {
@@ -6099,7 +6055,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
                         sslCertificateErrorDialogFragment.show(getSupportFragmentManager(), getString(R.string.ssl_certificate_error));
                     } catch (Exception exception) {
                         // Add the dialog to the pending dialog array list.  It will be displayed in `onStart()`.
-                        pendingDialogsArrayList.add(new PendingDialog(sslCertificateErrorDialogFragment, getString(R.string.ssl_certificate_error)));
+                        pendingDialogsArrayList.add(new PendingDialogDataClass(sslCertificateErrorDialogFragment, getString(R.string.ssl_certificate_error)));
                     }
                 }
             }