]> gitweb.stoutner.com Git - PrivacyBrowserAndroid.git/blobdiff - app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.java
Show the bottom app bar when opening a new tab. https://redmine.stoutner.com/issues/729
[PrivacyBrowserAndroid.git] / app / src / main / java / com / stoutner / privacybrowser / activities / MainWebViewActivity.java
index d89e287b9268f08fb06cc20f952a82c444f18cf0..d2881d7ebe8887c6d299ca1ec9b1b55cdc6b7e44 100644 (file)
@@ -107,6 +107,7 @@ import androidx.core.content.res.ResourcesCompat;
 import androidx.core.view.GravityCompat;
 import androidx.drawerlayout.widget.DrawerLayout;
 import androidx.fragment.app.DialogFragment;
+import androidx.fragment.app.Fragment;
 import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
 import androidx.viewpager.widget.ViewPager;
 import androidx.webkit.WebSettingsCompat;
@@ -126,6 +127,7 @@ 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.definitions.PendingDialog;
 import com.stoutner.privacybrowser.dialogs.AdConsentDialog;
 import com.stoutner.privacybrowser.dialogs.CreateBookmarkDialog;
 import com.stoutner.privacybrowser.dialogs.CreateBookmarkFolderDialog;
@@ -158,12 +160,16 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.io.UnsupportedEncodingException;
+
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.net.URLDecoder;
 import java.net.URLEncoder;
+
 import java.text.NumberFormat;
+
 import java.util.ArrayList;
+import java.util.Calendar;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -191,6 +197,9 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
     // `restartFromBookmarksActivity` is public static so it can be accessed from `BookmarksActivity`.  It is also used in `onRestart()`.
     public static boolean restartFromBookmarksActivity;
 
+    // Define the public static variables.
+    public static ArrayList<PendingDialog> pendingDialogsArrayList =  new ArrayList<>();
+
     // `currentBookmarksFolder` is public static so it can be accessed from `BookmarksActivity`.  It is also used in `onCreate()`, `onBackPressed()`, `onCreateBookmark()`, `onCreateBookmarkFolder()`,
     // `onSaveEditBookmark()`, `onSaveEditBookmarkFolder()`, and `loadBookmarksFolder()`.
     public static String currentBookmarksFolder;
@@ -247,40 +256,6 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
     private ArrayList<List<String[]>> ultraList;
     private ArrayList<List<String[]>> ultraPrivacy;
 
-    // `webViewDefaultUserAgent` is used in `onCreate()` and `onPrepareOptionsMenu()`.
-    private String webViewDefaultUserAgent;
-
-    // The incognito mode is set in `applyAppSettings()` and used in `initializeWebView()`.
-    private boolean incognitoModeEnabled;
-
-    // The full screen browsing mode tracker is set it `applyAppSettings()` and used in `initializeWebView()`.
-    private boolean fullScreenBrowsingModeEnabled;
-
-    // `inFullScreenBrowsingMode` is used in `onCreate()`, `onConfigurationChanged()`, and `applyAppSettings()`.
-    private boolean inFullScreenBrowsingMode;
-
-    // The app bar trackers are set in `applyAppSettings()` and used in `initializeWebView()`.
-    private boolean hideAppBar;
-    private boolean scrollAppBar;
-
-    // The loading new intent tracker is set in `onNewIntent()` and used in `setCurrentWebView()`.
-    private boolean loadingNewIntent;
-
-    // `reapplyDomainSettingsOnRestart` is used in `onCreate()`, `onOptionsItemSelected()`, `onNavigationItemSelected()`, `onRestart()`, and `onAddDomain()`, .
-    private boolean reapplyDomainSettingsOnRestart;
-
-    // `reapplyAppSettingsOnRestart` is used in `onNavigationItemSelected()` and `onRestart()`.
-    private boolean reapplyAppSettingsOnRestart;
-
-    // `displayingFullScreenVideo` is used in `onCreate()` and `onResume()`.
-    private boolean displayingFullScreenVideo;
-
-    // `orbotStatusBroadcastReceiver` is used in `onCreate()` and `onDestroy()`.
-    private BroadcastReceiver orbotStatusBroadcastReceiver;
-
-    // The waiting for proxy boolean is used in `onResume()`, `initializeApp()` and `applyProxy()`.
-    private boolean waitingForProxy = false;
-
     // The action bar drawer toggle is initialized in `onCreate()` and used in `onResume()`.
     private ActionBarDrawerToggle actionBarDrawerToggle;
 
@@ -315,6 +290,25 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
     private boolean sanitizeFacebookClickIds;
     private boolean sanitizeTwitterAmpRedirects;
 
+    // Declare the class variables
+    private BroadcastReceiver orbotStatusBroadcastReceiver;
+    private String webViewDefaultUserAgent;
+    private boolean incognitoModeEnabled;
+    private boolean fullScreenBrowsingModeEnabled;
+    private boolean inFullScreenBrowsingMode;
+    private boolean downloadWithExternalApp;
+    private boolean hideAppBar;
+    private boolean scrollAppBar;
+    private boolean bottomAppBar;
+    private boolean loadingNewIntent;
+    private boolean reapplyDomainSettingsOnRestart;
+    private boolean reapplyAppSettingsOnRestart;
+    private boolean displayingFullScreenVideo;
+    private boolean waitingForProxy;
+
+    // Define the class variables.
+    private long lastScrollUpdate = 0;
+
     // Declare the class views.
     private FrameLayout rootFrameLayout;
     private DrawerLayout drawerLayout;
@@ -341,8 +335,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
     private MenuItem navigationRequestsMenuItem;
     private MenuItem optionsPrivacyMenuItem;
     private MenuItem optionsRefreshMenuItem;
-    private MenuItem optionsFirstPartyCookiesMenuItem;
-    private MenuItem optionsThirdPartyCookiesMenuItem;
+    private MenuItem optionsCookiesMenuItem;
     private MenuItem optionsDomStorageMenuItem;
     private MenuItem optionsSaveFormDataMenuItem;
     private MenuItem optionsClearDataMenuItem;
@@ -405,9 +398,10 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
         // Get a handle for the shared preferences.
         SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
 
-        // Get the screenshot preference.
+        // Get the preferences.
         String appTheme = sharedPreferences.getString("app_theme", getString(R.string.app_theme_default_value));
         boolean allowScreenshots = sharedPreferences.getBoolean(getString(R.string.allow_screenshots_key), false);
+        bottomAppBar = sharedPreferences.getBoolean(getString(R.string.bottom_app_bar_key), false);
 
         // Get the theme entry values string array.
         String[] appThemeEntryValuesStringArray = getResources().getStringArray(R.array.app_theme_entry_values);
@@ -443,7 +437,11 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
         setTheme(R.style.PrivacyBrowser);
 
         // Set the content view.
-        setContentView(R.layout.main_framelayout);
+        if (bottomAppBar) {
+            setContentView(R.layout.main_framelayout_bottom_appbar);
+        } else {
+            setContentView(R.layout.main_framelayout_top_appbar);
+        }
 
         // Get handles for the views.
         rootFrameLayout = findViewById(R.id.root_framelayout);
@@ -538,6 +536,15 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
 
             // Only process the URI if it contains data or it is a web search.  If the user pressed the desktop icon after the app was already running the URI will be null.
             if (intentUriData != null || intentStringExtra != null || isWebSearch) {
+                // Exit the full screen video if it is displayed.
+                if (displayingFullScreenVideo) {
+                    // Exit full screen video mode.
+                    exitFullScreenVideo();
+
+                    // Reload the current WebView.  Otherwise, it can display entirely black.
+                    currentWebView.reload();
+                }
+
                 // Get the shared preferences.
                 SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
 
@@ -701,6 +708,18 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
             // Resume the ad.
             AdHelper.resumeAd(adView);
         }
+
+        // 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);
+
+            // Show the pending dialog.
+            pendingDialog.dialogFragment.show(getSupportFragmentManager(), pendingDialog.tag);
+        }
+
+        // Clear the pending dialogs array list.
+        pendingDialogsArrayList.clear();
     }
 
     // `onStop()` runs after `onPause()`.  It is used instead of `onPause()` so the commands are not called every time the screen is partially hidden.
@@ -822,8 +841,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
         // Get handles for the class menu items.
         optionsPrivacyMenuItem = menu.findItem(R.id.javascript);
         optionsRefreshMenuItem = menu.findItem(R.id.refresh);
-        optionsFirstPartyCookiesMenuItem = menu.findItem(R.id.first_party_cookies);
-        optionsThirdPartyCookiesMenuItem = menu.findItem(R.id.third_party_cookies);
+        optionsCookiesMenuItem = menu.findItem(R.id.cookies);
         optionsDomStorageMenuItem = menu.findItem(R.id.dom_storage);
         optionsSaveFormDataMenuItem = menu.findItem(R.id.save_form_data);  // Form data can be removed once the minimum API >= 26.
         optionsClearDataMenuItem = menu.findItem(R.id.clear_data);
@@ -871,9 +889,6 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
         // Set the initial status of the privacy icons.  `false` does not call `invalidateOptionsMenu` as the last step.
         updatePrivacyIcons(false);
 
-        // Only display third-party cookies if API >= 21
-        optionsThirdPartyCookiesMenuItem.setVisible(Build.VERSION.SDK_INT >= 21);
-
         // Only display the form data menu items if the API < 26.
         optionsSaveFormDataMenuItem.setVisible(Build.VERSION.SDK_INT < 26);
         optionsClearFormDataMenuItem.setVisible(Build.VERSION.SDK_INT < 26);
@@ -897,11 +912,11 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
         if (displayAdditionalAppBarIcons) {
             optionsRefreshMenuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
             bookmarksMenuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
-            optionsFirstPartyCookiesMenuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
+            optionsCookiesMenuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
         } else { //Do not display the additional icons.
             optionsRefreshMenuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
             bookmarksMenuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
-            optionsFirstPartyCookiesMenuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
+            optionsCookiesMenuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
         }
 
         // Replace Refresh with Stop if a URL is already loading.
@@ -975,15 +990,6 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
             optionsUltraPrivacyMenuItem.setTitle(currentWebView.getRequestsCount(NestedScrollWebView.ULTRAPRIVACY) + " - " + getString(R.string.ultraprivacy));
             optionsBlockAllThirdPartyRequestsMenuItem.setTitle(currentWebView.getRequestsCount(NestedScrollWebView.THIRD_PARTY_REQUESTS) + " - " + getString(R.string.block_all_third_party_requests));
 
-            // Only modify third-party cookies if the API >= 21.
-            if (Build.VERSION.SDK_INT >= 21) {
-                // Set the status of the third-party cookies checkbox.
-                optionsThirdPartyCookiesMenuItem.setChecked(cookieManager.acceptThirdPartyCookies(currentWebView));
-
-                // Enable third-party cookies if first-party cookies are enabled.
-                optionsThirdPartyCookiesMenuItem.setEnabled(cookieManager.acceptCookie());
-            }
-
             // Enable DOM Storage if JavaScript is enabled.
             optionsDomStorageMenuItem.setEnabled(currentWebView.getSettings().getJavaScriptEnabled());
 
@@ -993,8 +999,8 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
             }
         }
 
-        // Set the checked status of the first party cookies menu item.
-        optionsFirstPartyCookiesMenuItem.setChecked(cookieManager.acceptCookie());
+        // Set the cookies menu item checked status.
+        optionsCookiesMenuItem.setChecked(cookieManager.acceptCookie());
 
         // Enable Clear Cookies if there are any.
         optionsClearCookiesMenuItem.setEnabled(cookieManager.hasCookies());
@@ -1213,12 +1219,12 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
 
             // Consume the event.
             return true;
-        } else if (menuItemId == R.id.first_party_cookies) {  // First-party cookies.
+        } else if (menuItemId == R.id.cookies) {  // Cookies.
             // Switch the first-party cookie status.
             cookieManager.setAcceptCookie(!cookieManager.acceptCookie());
 
-            // Store the first-party cookie status.
-            currentWebView.setAcceptFirstPartyCookies(cookieManager.acceptCookie());
+            // Store the cookie status.
+            currentWebView.setAcceptCookies(cookieManager.acceptCookie());
 
             // Update the menu checkbox.
             menuItem.setChecked(cookieManager.acceptCookie());
@@ -1227,10 +1233,10 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
             updatePrivacyIcons(true);
 
             // Display a snackbar.
-            if (cookieManager.acceptCookie()) {  // First-party cookies are enabled.
-                Snackbar.make(webViewPager, R.string.first_party_cookies_enabled, Snackbar.LENGTH_SHORT).show();
+            if (cookieManager.acceptCookie()) {  // Cookies are enabled.
+                Snackbar.make(webViewPager, R.string.cookies_enabled, Snackbar.LENGTH_SHORT).show();
             } else if (currentWebView.getSettings().getJavaScriptEnabled()) {  // JavaScript is still enabled.
-                Snackbar.make(webViewPager, R.string.first_party_cookies_disabled, Snackbar.LENGTH_SHORT).show();
+                Snackbar.make(webViewPager, R.string.cookies_disabled, Snackbar.LENGTH_SHORT).show();
             } else {  // Privacy mode.
                 Snackbar.make(webViewPager, R.string.privacy_mode, Snackbar.LENGTH_SHORT).show();
             }
@@ -1238,28 +1244,6 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
             // Reload the current WebView.
             currentWebView.reload();
 
-            // Consume the event.
-            return true;
-        } else if (menuItemId == R.id.third_party_cookies) {  // Third-party cookies.
-            // Only act if the API >= 21.  Otherwise, there are no third-party cookie controls.
-            if (Build.VERSION.SDK_INT >= 21) {
-                // Toggle the status of thirdPartyCookiesEnabled.
-                cookieManager.setAcceptThirdPartyCookies(currentWebView, !cookieManager.acceptThirdPartyCookies(currentWebView));
-
-                // Update the menu checkbox.
-                menuItem.setChecked(cookieManager.acceptThirdPartyCookies(currentWebView));
-
-                // Display a snackbar.
-                if (cookieManager.acceptThirdPartyCookies(currentWebView)) {
-                    Snackbar.make(webViewPager, R.string.third_party_cookies_enabled, Snackbar.LENGTH_SHORT).show();
-                } else {
-                    Snackbar.make(webViewPager, R.string.third_party_cookies_disabled, Snackbar.LENGTH_SHORT).show();
-                }
-
-                // Reload the current WebView.
-                currentWebView.reload();
-            }
-
             // Consume the event.
             return true;
         } else if (menuItemId == R.id.dom_storage) {  // DOM storage.
@@ -1438,7 +1422,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
             // Update the menu checkbox.
             menuItem.setChecked(currentWebView.isBlocklistEnabled(NestedScrollWebView.FANBOYS_ANNOYANCE_LIST));
 
-            // Update the staus of Fanboy's Social Blocking List.
+            // Update the status of Fanboy's Social Blocking List.
             optionsFanboysSocialBlockingListMenuItem.setEnabled(!currentWebView.isBlocklistEnabled(NestedScrollWebView.FANBOYS_ANNOYANCE_LIST));
 
             // Reload the current WebView.
@@ -1756,9 +1740,14 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
             // Consume the event.
             return true;
         } else if (menuItemId == R.id.save_url) {  // Save URL.
-            // 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(), SaveWebpageDialog.SAVE_URL, currentWebView.getSettings().getUserAgentString(),
-                    currentWebView.getAcceptFirstPartyCookies()).execute(currentWebView.getCurrentUrl());
+            // Check the download preference.
+            if (downloadWithExternalApp) {  // Download with an external app.
+                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(), SaveWebpageDialog.SAVE_URL, currentWebView.getSettings().getUserAgentString(),
+                        currentWebView.getAcceptCookies()).execute(currentWebView.getCurrentUrl());
+            }
 
             // Consume the event.
             return true;
@@ -2156,7 +2145,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
                     ultraList.get(0).get(0)[0], ultraPrivacy.get(0).get(0)[0]};
 
             // Add the blocklist versions to the intent.
-            aboutIntent.putExtra("blocklist_versions", blocklistVersions);
+            aboutIntent.putExtra(AboutActivity.BLOCKLIST_VERSIONS, blocklistVersions);
 
             // Make it so.
             startActivity(aboutIntent);
@@ -2269,9 +2258,14 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
 
                 // Add a Save URL entry.
                 menu.add(R.string.save_url).setOnMenuItemClickListener((MenuItem item) -> {
-                    // 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(), SaveWebpageDialog.SAVE_URL, currentWebView.getSettings().getUserAgentString(),
-                            currentWebView.getAcceptFirstPartyCookies()).execute(linkUrl);
+                    // Check the download preference.
+                    if (downloadWithExternalApp) {  // Download with an external app.
+                        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(), SaveWebpageDialog.SAVE_URL, currentWebView.getSettings().getUserAgentString(),
+                                currentWebView.getAcceptCookies()).execute(linkUrl);
+                    }
 
                     // Consume the event.
                     return true;
@@ -2336,9 +2330,14 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
 
                 // Add a Save Image entry.
                 menu.add(R.string.save_image).setOnMenuItemClickListener((MenuItem item) -> {
-                   // 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(), SaveWebpageDialog.SAVE_URL, currentWebView.getSettings().getUserAgentString(),
-                            currentWebView.getAcceptFirstPartyCookies()).execute(imageUrl);
+                    // Check the download preference.
+                    if (downloadWithExternalApp) {  // Download with an external app.
+                        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(), SaveWebpageDialog.SAVE_URL, currentWebView.getSettings().getUserAgentString(),
+                                currentWebView.getAcceptCookies()).execute(imageUrl);
+                    }
 
                     // Consume the event.
                     return true;
@@ -2436,9 +2435,14 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
 
                 // Add a Save Image entry.
                 menu.add(R.string.save_image).setOnMenuItemClickListener((MenuItem item) -> {
-                    // 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(), SaveWebpageDialog.SAVE_URL, currentWebView.getSettings().getUserAgentString(),
-                            currentWebView.getAcceptFirstPartyCookies()).execute(imageUrl);
+                    // Check the download preference.
+                    if (downloadWithExternalApp) {  // Download with an external app.
+                        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(), SaveWebpageDialog.SAVE_URL, currentWebView.getSettings().getUserAgentString(),
+                                currentWebView.getAcceptCookies()).execute(imageUrl);
+                    }
 
                     // Consume the event.
                     return true;
@@ -2458,9 +2462,14 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
 
                 // Add a Save URL entry.
                 menu.add(R.string.save_url).setOnMenuItemClickListener((MenuItem item) -> {
-                    // 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(), SaveWebpageDialog.SAVE_URL, currentWebView.getSettings().getUserAgentString(),
-                            currentWebView.getAcceptFirstPartyCookies()).execute(linkUrl);
+                    // Check the download preference.
+                    if (downloadWithExternalApp) {  // Download with an external app.
+                        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(), SaveWebpageDialog.SAVE_URL, currentWebView.getSettings().getUserAgentString(),
+                                currentWebView.getAcceptCookies()).execute(linkUrl);
+                    }
 
                     // Consume the event.
                     return true;
@@ -2729,62 +2738,8 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
             // close the bookmarks drawer.
             drawerLayout.closeDrawer(GravityCompat.END);
         } else if (displayingFullScreenVideo) {  // A full screen video is shown.
-            // Re-enable the screen timeout.
-            fullScreenVideoFrameLayout.setKeepScreenOn(false);
-
-            // Unset the full screen video flag.
-            displayingFullScreenVideo = false;
-
-            // Remove all the views from the full screen video frame layout.
-            fullScreenVideoFrameLayout.removeAllViews();
-
-            // Hide the full screen video frame layout.
-            fullScreenVideoFrameLayout.setVisibility(View.GONE);
-
-            // Enable the sliding drawers.
-            drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
-
-            // Show the main content relative layout.
-            mainContentRelativeLayout.setVisibility(View.VISIBLE);
-
-            // Apply the appropriate full screen mode flags.
-            if (fullScreenBrowsingModeEnabled && inFullScreenBrowsingMode) {  // Privacy Browser is currently in full screen browsing mode.
-                // Hide the banner ad in the free flavor.
-                if (BuildConfig.FLAVOR.contentEquals("free")) {
-                    // Get a handle for the ad view.  This cannot be a class variable because it changes with each ad load.
-                    View adView = findViewById(R.id.adview);
-
-                    // Hide the banner ad.
-                    AdHelper.hideAd(adView);
-                }
-
-                /* Hide the system bars.
-                 * SYSTEM_UI_FLAG_FULLSCREEN hides the status bar at the top of the screen.
-                 * SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN makes the root frame layout fill the area that is normally reserved for the status bar.
-                 * SYSTEM_UI_FLAG_HIDE_NAVIGATION hides the navigation bar on the bottom or right of the screen.
-                 * SYSTEM_UI_FLAG_IMMERSIVE_STICKY makes the status and navigation bars translucent and automatically re-hides them after they are shown.
-                 */
-                rootFrameLayout.setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
-                        View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
-
-                // Reload the website if the app bar is hidden.  Otherwise, there is some bug in Android that causes the WebView to be entirely black.
-                if (hideAppBar) {
-                    // Reload the WebView.
-                    currentWebView.reload();
-                }
-            } else {  // Switch to normal viewing mode.
-                // Remove the `SYSTEM_UI` flags from the root frame layout.
-                rootFrameLayout.setSystemUiVisibility(0);
-            }
-
-            // Reload the ad for the free flavor if not in full screen mode.
-            if (BuildConfig.FLAVOR.contentEquals("free") && !inFullScreenBrowsingMode) {
-                // Get a handle for the ad view.  This cannot be a class variable because it changes with each ad load.
-                View adView = findViewById(R.id.adview);
-
-                // Reload the ad.  `getContext()` can be used instead of `getActivity.getApplicationContext()` once the minimum API >= 23.
-                AdHelper.loadAd(adView, getApplicationContext(), this, getString(R.string.ad_unit_id));
-            }
+            // Exit the full screen video.
+            exitFullScreenVideo();
         } else if (currentWebView.canGoBack()) {  // There is at least one item in the current WebView history.
             // Get the current web back forward list.
             WebBackForwardList webBackForwardList = currentWebView.copyBackForwardList();
@@ -3098,7 +3053,20 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
         }
     }
 
-    @Override
+    private void downloadUrlWithExternalApp(String url) {
+        // Create a download intent.  Not specifying the action type will display the maximum number of options.
+        Intent downloadIntent = new Intent();
+
+        // Set the URI and the mime type.
+        downloadIntent.setDataAndType(Uri.parse(url), "text/html");
+
+        // Flag the intent to open in a new task.
+        downloadIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+        // Show the chooser.
+        startActivity(Intent.createChooser(downloadIntent, getString(R.string.download_with_external_app)));
+    }
+
     public void onSaveWebpage(int saveType, @NonNull String originalUrlString, DialogFragment dialogFragment) {
         // Get the dialog.
         Dialog dialog = dialogFragment.getDialog();
@@ -3131,7 +3099,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
                 }
 
                 // Save the URL.
-                new SaveUrl(this, this, saveWebpageFilePath, currentWebView.getSettings().getUserAgentString(), currentWebView.getAcceptFirstPartyCookies()).execute(saveWebpageUrl);
+                new SaveUrl(this, this, saveWebpageFilePath, currentWebView.getSettings().getUserAgentString(), currentWebView.getAcceptCookies()).execute(saveWebpageUrl);
                 break;
 
             case SaveWebpageDialog.SAVE_ARCHIVE:
@@ -3191,7 +3159,9 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
                 break;
         }
     }
-
+    
+    // Remove the warning that `OnTouchListener()` needs to override `performClick()`, as the only purpose of setting the `OnTouchListener()` is to make it do nothing.
+    @SuppressLint("ClickableViewAccessibility")
     private void initializeApp() {
         // Get a handle for the input method.
         InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
@@ -3256,12 +3226,19 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
                     // Reset the waiting for proxy status.
                     waitingForProxy = false;
 
-                    // Get a handle for the waiting for proxy dialog.
-                    DialogFragment waitingForProxyDialogFragment = (DialogFragment) getSupportFragmentManager().findFragmentByTag(getString(R.string.waiting_for_proxy_dialog));
+                    // Get a list of the current fragments.
+                    List<Fragment> fragmentList = getSupportFragmentManager().getFragments();
 
-                    // Dismiss the waiting for proxy dialog if it is displayed.
-                    if (waitingForProxyDialogFragment != null) {
-                        waitingForProxyDialogFragment.dismiss();
+                    // Check each fragment to see if it is a waiting for proxy dialog.  Sometimes more than one is displayed.
+                    for (int i = 0; i < fragmentList.size(); i++) {
+                        // Get the fragment tag.
+                        String fragmentTag = fragmentList.get(i).getTag();
+
+                        // Check to see if it is the waiting for proxy dialog.
+                        if ((fragmentTag!= null) && fragmentTag.equals(getString(R.string.waiting_for_proxy_dialog))) {
+                            // Dismiss the waiting for proxy dialog.
+                            ((DialogFragment) fragmentList.get(i)).dismiss();
+                        }
                     }
 
                     // Reload existing URLs and load any URLs that are waiting for the proxy.
@@ -3301,6 +3278,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
         this.registerReceiver(orbotStatusBroadcastReceiver, new IntentFilter("org.torproject.android.intent.action.STATUS"));
 
         // Get handles for views that need to be modified.
+        LinearLayout bookmarksHeaderLinearLayout = findViewById(R.id.bookmarks_header_linearlayout);
         ListView bookmarksListView = findViewById(R.id.bookmarks_drawer_listview);
         FloatingActionButton launchBookmarksActivityFab = findViewById(R.id.launch_bookmarks_activity_fab);
         FloatingActionButton createBookmarkFolderFab = findViewById(R.id.create_bookmark_folder_fab);
@@ -3367,6 +3345,12 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
             }
         });
 
+        // Set a touch listener on the bookmarks header linear layout so that touches don't pass through to the button underneath.
+        bookmarksHeaderLinearLayout.setOnTouchListener((view, motionEvent) -> {
+            // Consume the touch.
+            return true;
+        });
+
         // Set the launch bookmarks activity FAB to launch the bookmarks activity.
         launchBookmarksActivityFab.setOnClickListener(v -> {
             // Get a copy of the favorite icon bitmap.
@@ -3448,7 +3432,19 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
         });
 
         // Implement swipe to refresh.
-        swipeRefreshLayout.setOnRefreshListener(() -> currentWebView.reload());
+        swipeRefreshLayout.setOnRefreshListener(() -> {
+            // Check the visibility of the bottom app bar.  Sometimes it is hidden if the WebView is the same size as the visible screen.
+            if (bottomAppBar && scrollAppBar && (appBarLayout.getVisibility() == View.GONE)) {  // The bottom app bar is currently hidden.
+                // Show the app bar.
+                appBarLayout.setVisibility(View.VISIBLE);
+
+                // Disable the refreshing animation.
+                swipeRefreshLayout.setRefreshing(false);
+            } else {  // A bottom app bar is not currently hidden.
+                // Reload the website.
+                currentWebView.reload();
+            }
+        });
 
         // Store the default progress view offsets for use later in `initializeWebView()`.
         defaultProgressViewStartOffset = swipeRefreshLayout.getProgressViewStartOffset();
@@ -3522,7 +3518,8 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
             // Find out if the selected bookmark is a folder.
             boolean isFolder = bookmarksDatabaseHelper.isFolder(databaseId);
 
-            if (isFolder) {
+            // Check to see if the bookmark is a folder.
+            if (isFolder) {  // The bookmark is a folder.
                 // Save the current folder name, which is used in `onSaveEditBookmarkFolder()`.
                 oldFolderNameString = bookmarksCursor.getString(bookmarksCursor.getColumnIndex(BookmarksDatabaseHelper.BOOKMARK_NAME));
 
@@ -3531,7 +3528,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
 
                 // Show the edit folder bookmark dialog.
                 editBookmarkFolderDialog.show(getSupportFragmentManager(), getString(R.string.edit_folder));
-            } else {
+            } else {  // The bookmark is not a folder.
                 // Get the bookmark cursor for this ID.
                 Cursor bookmarkCursor = bookmarksDatabaseHelper.getBookmark(databaseId);
 
@@ -3540,6 +3537,9 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
 
                 // Load the bookmark in a new tab but do not switch to the tab or close the drawer.
                 addNewTab(bookmarkCursor.getString(bookmarkCursor.getColumnIndex(BookmarksDatabaseHelper.BOOKMARK_URL)), false);
+
+                // Display a snackbar.
+                Snackbar.make(currentWebView, R.string.bookmark_opened_in_background, Snackbar.LENGTH_SHORT).show();
             }
 
             // Consume the event.
@@ -3610,6 +3610,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
         sanitizeTwitterAmpRedirects = sharedPreferences.getBoolean("twitter_amp_redirects", true);
         proxyMode = sharedPreferences.getString("proxy", getString(R.string.proxy_default_value));
         fullScreenBrowsingModeEnabled = sharedPreferences.getBoolean("full_screen_browsing_mode", false);
+        downloadWithExternalApp = sharedPreferences.getBoolean(getString(R.string.download_with_external_app_key), false);
         hideAppBar = sharedPreferences.getBoolean("hide_app_bar", true);
         scrollAppBar = sharedPreferences.getBoolean("scroll_app_bar", true);
 
@@ -3635,51 +3636,48 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
         // Apply the proxy.
         applyProxy(false);
 
-        // Get the current layout parameters.  Using coordinator layout parameters allows the `setBehavior()` command and using app bar layout parameters allows the `setScrollFlags()` command.
-        CoordinatorLayout.LayoutParams swipeRefreshLayoutParams = (CoordinatorLayout.LayoutParams) swipeRefreshLayout.getLayoutParams();
-        AppBarLayout.LayoutParams toolbarLayoutParams = (AppBarLayout.LayoutParams) toolbar.getLayoutParams();
-        AppBarLayout.LayoutParams findOnPageLayoutParams = (AppBarLayout.LayoutParams) findOnPageLinearLayout.getLayoutParams();
-        AppBarLayout.LayoutParams tabsLayoutParams = (AppBarLayout.LayoutParams) tabsLinearLayout.getLayoutParams();
-
-        // Add the scrolling behavior to the layout parameters.
-        if (scrollAppBar) {
-            // Enable scrolling of the app bar.
-            swipeRefreshLayoutParams.setBehavior(new AppBarLayout.ScrollingViewBehavior());
-            toolbarLayoutParams.setScrollFlags(AppBarLayout.LayoutParams.SCROLL_FLAG_SCROLL | AppBarLayout.LayoutParams.SCROLL_FLAG_ENTER_ALWAYS | AppBarLayout.LayoutParams.SCROLL_FLAG_SNAP);
-            findOnPageLayoutParams.setScrollFlags(AppBarLayout.LayoutParams.SCROLL_FLAG_SCROLL | AppBarLayout.LayoutParams.SCROLL_FLAG_ENTER_ALWAYS | AppBarLayout.LayoutParams.SCROLL_FLAG_SNAP);
-            tabsLayoutParams.setScrollFlags(AppBarLayout.LayoutParams.SCROLL_FLAG_SCROLL | AppBarLayout.LayoutParams.SCROLL_FLAG_ENTER_ALWAYS | AppBarLayout.LayoutParams.SCROLL_FLAG_SNAP);
-        } else {
-            // Disable scrolling of the app bar.
-            swipeRefreshLayoutParams.setBehavior(null);
-            toolbarLayoutParams.setScrollFlags(0);
-            findOnPageLayoutParams.setScrollFlags(0);
-            tabsLayoutParams.setScrollFlags(0);
-
-            // Expand the app bar if it is currently collapsed.
-            appBarLayout.setExpanded(true);
-        }
-
-        // Apply the modified layout parameters.
-        swipeRefreshLayout.setLayoutParams(swipeRefreshLayoutParams);
-        toolbar.setLayoutParams(toolbarLayoutParams);
-        findOnPageLinearLayout.setLayoutParams(findOnPageLayoutParams);
-        tabsLinearLayout.setLayoutParams(tabsLayoutParams);
+        // Adjust the layout and scrolling parameters if the app bar is at the top of the screen.
+        if (!bottomAppBar) {
+            // Get the current layout parameters.  Using coordinator layout parameters allows the `setBehavior()` command and using app bar layout parameters allows the `setScrollFlags()` command.
+            CoordinatorLayout.LayoutParams swipeRefreshLayoutParams = (CoordinatorLayout.LayoutParams) swipeRefreshLayout.getLayoutParams();
+            AppBarLayout.LayoutParams toolbarLayoutParams = (AppBarLayout.LayoutParams) toolbar.getLayoutParams();
+            AppBarLayout.LayoutParams findOnPageLayoutParams = (AppBarLayout.LayoutParams) findOnPageLinearLayout.getLayoutParams();
+            AppBarLayout.LayoutParams tabsLayoutParams = (AppBarLayout.LayoutParams) tabsLinearLayout.getLayoutParams();
+
+            // Add the scrolling behavior to the layout parameters.
+            if (scrollAppBar) {
+                // Enable scrolling of the app bar.
+                swipeRefreshLayoutParams.setBehavior(new AppBarLayout.ScrollingViewBehavior());
+                toolbarLayoutParams.setScrollFlags(AppBarLayout.LayoutParams.SCROLL_FLAG_SCROLL | AppBarLayout.LayoutParams.SCROLL_FLAG_ENTER_ALWAYS | AppBarLayout.LayoutParams.SCROLL_FLAG_SNAP);
+                findOnPageLayoutParams.setScrollFlags(AppBarLayout.LayoutParams.SCROLL_FLAG_SCROLL | AppBarLayout.LayoutParams.SCROLL_FLAG_ENTER_ALWAYS | AppBarLayout.LayoutParams.SCROLL_FLAG_SNAP);
+                tabsLayoutParams.setScrollFlags(AppBarLayout.LayoutParams.SCROLL_FLAG_SCROLL | AppBarLayout.LayoutParams.SCROLL_FLAG_ENTER_ALWAYS | AppBarLayout.LayoutParams.SCROLL_FLAG_SNAP);
+            } else {
+                // Disable scrolling of the app bar.
+                swipeRefreshLayoutParams.setBehavior(null);
+                toolbarLayoutParams.setScrollFlags(0);
+                findOnPageLayoutParams.setScrollFlags(0);
+                tabsLayoutParams.setScrollFlags(0);
+
+                // Expand the app bar if it is currently collapsed.
+                appBarLayout.setExpanded(true);
+            }
 
-        // Set the app bar scrolling for each WebView.
-        for (int i = 0; i < webViewPagerAdapter.getCount(); i++) {
-            // Get the WebView tab fragment.
-            WebViewTabFragment webViewTabFragment = webViewPagerAdapter.getPageFragment(i);
+            // Set the app bar scrolling for each WebView.
+            for (int i = 0; i < webViewPagerAdapter.getCount(); i++) {
+                // Get the WebView tab fragment.
+                WebViewTabFragment webViewTabFragment = webViewPagerAdapter.getPageFragment(i);
 
-            // Get the fragment view.
-            View fragmentView = webViewTabFragment.getView();
+                // Get the fragment view.
+                View fragmentView = webViewTabFragment.getView();
 
-            // Only modify the WebViews if they exist.
-            if (fragmentView != null) {
-                // Get the nested scroll WebView from the tab fragment.
-                NestedScrollWebView nestedScrollWebView = fragmentView.findViewById(R.id.nestedscroll_webview);
+                // Only modify the WebViews if they exist.
+                if (fragmentView != null) {
+                    // Get the nested scroll WebView from the tab fragment.
+                    NestedScrollWebView nestedScrollWebView = fragmentView.findViewById(R.id.nestedscroll_webview);
 
-                // Set the app bar scrolling.
-                nestedScrollWebView.setNestedScrollingEnabled(scrollAppBar);
+                    // Set the app bar scrolling.
+                    nestedScrollWebView.setNestedScrollingEnabled(scrollAppBar);
+                }
             }
         }
 
@@ -3909,8 +3907,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
                 // Get the settings from the cursor.
                 nestedScrollWebView.setDomainSettingsDatabaseId(currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper._ID)));
                 nestedScrollWebView.getSettings().setJavaScriptEnabled(currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_JAVASCRIPT)) == 1);
-                nestedScrollWebView.setAcceptFirstPartyCookies(currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FIRST_PARTY_COOKIES)) == 1);
-                boolean domainThirdPartyCookiesEnabled = (currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_THIRD_PARTY_COOKIES)) == 1);
+                nestedScrollWebView.setAcceptCookies(currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.COOKIES)) == 1);
                 nestedScrollWebView.getSettings().setDomStorageEnabled(currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_DOM_STORAGE)) == 1);
                 // Form data can be removed once the minimum API >= 26.
                 boolean saveFormData = (currentDomainSettingsCursor.getInt(currentDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FORM_DATA)) == 1);
@@ -3980,12 +3977,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
                 }
 
                 // Apply the cookie domain settings.
-                cookieManager.setAcceptCookie(nestedScrollWebView.getAcceptFirstPartyCookies());
-
-                // Set third-party cookies status if API >= 21.
-                if (Build.VERSION.SDK_INT >= 21) {
-                    cookieManager.setAcceptThirdPartyCookies(nestedScrollWebView, domainThirdPartyCookiesEnabled);
-                }
+                cookieManager.setAcceptCookie(nestedScrollWebView.getAcceptCookies());
 
                 // Apply the form data setting if the API < 26.
                 if (Build.VERSION.SDK_INT < 26) {
@@ -4164,8 +4156,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
             } else {  // The new URL does not have custom domain settings.  Load the defaults.
                 // Store the values from the shared preferences.
                 nestedScrollWebView.getSettings().setJavaScriptEnabled(sharedPreferences.getBoolean("javascript", false));
-                nestedScrollWebView.setAcceptFirstPartyCookies(sharedPreferences.getBoolean("first_party_cookies", false));
-                boolean defaultThirdPartyCookiesEnabled = sharedPreferences.getBoolean("third_party_cookies", false);
+                nestedScrollWebView.setAcceptCookies(sharedPreferences.getBoolean(getString(R.string.cookies_key), false));
                 nestedScrollWebView.getSettings().setDomStorageEnabled(sharedPreferences.getBoolean("dom_storage", false));
                 boolean saveFormData = sharedPreferences.getBoolean("save_form_data", false);  // Form data can be removed once the minimum API >= 26.
                 nestedScrollWebView.enableBlocklist(NestedScrollWebView.EASYLIST, sharedPreferences.getBoolean("easylist", true));
@@ -4176,8 +4167,8 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
                 nestedScrollWebView.enableBlocklist(NestedScrollWebView.ULTRAPRIVACY, sharedPreferences.getBoolean("ultraprivacy", true));
                 nestedScrollWebView.enableBlocklist(NestedScrollWebView.THIRD_PARTY_REQUESTS, sharedPreferences.getBoolean("block_all_third_party_requests", false));
 
-                // Apply the default first-party cookie setting.
-                cookieManager.setAcceptCookie(nestedScrollWebView.getAcceptFirstPartyCookies());
+                // Apply the default cookie setting.
+                cookieManager.setAcceptCookie(nestedScrollWebView.getAcceptCookies());
 
                 // Apply the default font size setting.
                 try {
@@ -4208,11 +4199,6 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
                 // Reset the pinned variables.
                 nestedScrollWebView.setDomainSettingsDatabaseId(-1);
 
-                // Set third-party cookies status if API >= 21.
-                if (Build.VERSION.SDK_INT >= 21) {
-                    cookieManager.setAcceptThirdPartyCookies(nestedScrollWebView, defaultThirdPartyCookiesEnabled);
-                }
-
                 // Get the array position of the user agent name.
                 int userAgentArrayPosition = userAgentNamesArray.getPosition(defaultUserAgentName);
 
@@ -4342,8 +4328,14 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
                             // Get a handle for the waiting for proxy alert dialog.
                             DialogFragment waitingForProxyDialogFragment = new WaitingForProxyDialog();
 
-                            // Display the waiting for proxy alert dialog.
-                            waitingForProxyDialogFragment.show(getSupportFragmentManager(), getString(R.string.waiting_for_proxy_dialog));
+                            // Try to show the dialog.  Sometimes the window is not yet active if returning from Settings.
+                            try {
+                                // Show the waiting for proxy alert dialog.
+                                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)));
+                            }
                         }
                     }
                 } catch (PackageManager.NameNotFoundException exception) {  // Orbot is not installed.
@@ -4352,8 +4344,14 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
                         // Get a handle for the Orbot not installed alert dialog.
                         DialogFragment orbotNotInstalledDialogFragment = ProxyNotInstalledDialog.displayDialog(proxyMode);
 
-                        // Display the Orbot not installed alert dialog.
-                        orbotNotInstalledDialogFragment.show(getSupportFragmentManager(), getString(R.string.proxy_not_installed_dialog));
+                        // Try to show the dialog.  Sometimes the window is not yet active if returning from Settings.
+                        try {
+                            // Display the Orbot not installed alert dialog.
+                            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)));
+                        }
                     }
                 }
                 break;
@@ -4379,8 +4377,14 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
                         // Get a handle for the waiting for proxy alert dialog.
                         DialogFragment i2pNotInstalledDialogFragment = ProxyNotInstalledDialog.displayDialog(proxyMode);
 
-                        // Display the I2P not installed alert dialog.
-                        i2pNotInstalledDialogFragment.show(getSupportFragmentManager(), getString(R.string.proxy_not_installed_dialog));
+                        // Try to show the dialog.  Sometimes the window is not yet active if returning from Settings.
+                        try {
+                            // Display the I2P not installed alert dialog.
+                            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)));
+                        }
                     }
                 }
                 break;
@@ -4423,7 +4427,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
             // Update the privacy icon.
             if (currentWebView.getSettings().getJavaScriptEnabled()) {  // JavaScript is enabled.
                 optionsPrivacyMenuItem.setIcon(R.drawable.javascript_enabled);
-            } else if (currentWebView.getAcceptFirstPartyCookies()) {  // JavaScript is disabled but cookies are enabled.
+            } else if (currentWebView.getAcceptCookies()) {  // JavaScript is disabled but cookies are enabled.
                 optionsPrivacyMenuItem.setIcon(R.drawable.warning);
             } else {  // All the dangerous features are disabled.
                 optionsPrivacyMenuItem.setIcon(R.drawable.privacy_mode);
@@ -4432,14 +4436,14 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
             // Get the current theme status.
             int currentThemeStatus = getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
 
-            // Update the first-party cookies icon.
-            if (currentWebView.getAcceptFirstPartyCookies()) {  // First-party cookies are enabled.
-                optionsFirstPartyCookiesMenuItem.setIcon(R.drawable.cookies_enabled);
-            } else {  // First-party cookies are disabled.
+            // Update the cookies icon.
+            if (currentWebView.getAcceptCookies()) {  // Cookies are enabled.
+                optionsCookiesMenuItem.setIcon(R.drawable.cookies_enabled);
+            } else {  // Cookies are disabled.
                 if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) {
-                    optionsFirstPartyCookiesMenuItem.setIcon(R.drawable.cookies_disabled_day);
+                    optionsCookiesMenuItem.setIcon(R.drawable.cookies_disabled_day);
                 } else {
-                    optionsFirstPartyCookiesMenuItem.setIcon(R.drawable.cookies_disabled_night);
+                    optionsCookiesMenuItem.setIcon(R.drawable.cookies_disabled_night);
                 }
             }
 
@@ -4529,11 +4533,11 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
         // Update the bookmarks cursor with the contents of the bookmarks database for the current folder.
         bookmarksCursor = bookmarksDatabaseHelper.getBookmarksByDisplayOrder(currentBookmarksFolder);
 
-        // Populate the bookmarks cursor adapter.  `this` specifies the `Context`.  `false` disables `autoRequery`.
+        // Populate the bookmarks cursor adapter.
         bookmarksCursorAdapter = new CursorAdapter(this, bookmarksCursor, false) {
             @Override
             public View newView(Context context, Cursor cursor, ViewGroup parent) {
-                // Inflate the individual item layout.  `false` does not attach it to the root.
+                // Inflate the individual item layout.
                 return getLayoutInflater().inflate(R.layout.bookmarks_drawer_item_linearlayout, parent, false);
             }
 
@@ -4801,6 +4805,11 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
 
         // Add the new WebView page.
         webViewPagerAdapter.addPage(newTabNumber, webViewPager, url, moveToTab);
+
+        // Show the app bar if it is at the bottom of the screen and the new tab is taking focus.
+        if (bottomAppBar && moveToTab) {
+            appBarLayout.setVisibility(View.VISIBLE);
+        }
     }
 
     public void closeTab(View view) {
@@ -4827,6 +4836,68 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
         }
     }
 
+    private void exitFullScreenVideo() {
+        // Re-enable the screen timeout.
+        fullScreenVideoFrameLayout.setKeepScreenOn(false);
+
+        // Unset the full screen video flag.
+        displayingFullScreenVideo = false;
+
+        // Remove all the views from the full screen video frame layout.
+        fullScreenVideoFrameLayout.removeAllViews();
+
+        // Hide the full screen video frame layout.
+        fullScreenVideoFrameLayout.setVisibility(View.GONE);
+
+        // Enable the sliding drawers.
+        drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
+
+        // Show the main content relative layout.
+        mainContentRelativeLayout.setVisibility(View.VISIBLE);
+
+        // Apply the appropriate full screen mode flags.
+        if (fullScreenBrowsingModeEnabled && inFullScreenBrowsingMode) {  // Privacy Browser is currently in full screen browsing mode.
+            // Hide the app bar if specified.
+            if (hideAppBar) {
+                // Hide the tab linear layout.
+                tabsLinearLayout.setVisibility(View.GONE);
+
+                // Hide the action bar.
+                actionBar.hide();
+            }
+
+            // Hide the banner ad in the free flavor.
+            if (BuildConfig.FLAVOR.contentEquals("free")) {
+                // Get a handle for the ad view.  This cannot be a class variable because it changes with each ad load.
+                View adView = findViewById(R.id.adview);
+
+                // Hide the banner ad.
+                AdHelper.hideAd(adView);
+            }
+
+            /* Hide the system bars.
+             * SYSTEM_UI_FLAG_FULLSCREEN hides the status bar at the top of the screen.
+             * SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN makes the root frame layout fill the area that is normally reserved for the status bar.
+             * SYSTEM_UI_FLAG_HIDE_NAVIGATION hides the navigation bar on the bottom or right of the screen.
+             * SYSTEM_UI_FLAG_IMMERSIVE_STICKY makes the status and navigation bars translucent and automatically re-hides them after they are shown.
+             */
+            rootFrameLayout.setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
+                    View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
+        } else {  // Switch to normal viewing mode.
+            // Remove the `SYSTEM_UI` flags from the root frame layout.
+            rootFrameLayout.setSystemUiVisibility(0);
+        }
+
+        // Reload the ad for the free flavor if not in full screen mode.
+        if (BuildConfig.FLAVOR.contentEquals("free") && !inFullScreenBrowsingMode) {
+            // Get a handle for the ad view.  This cannot be a class variable because it changes with each ad load.
+            View adView = findViewById(R.id.adview);
+
+            // Reload the ad.
+            AdHelper.loadAd(adView, this, this, getString(R.string.ad_unit_id));
+        }
+    }
+
     private void clearAndExit() {
         // Get a handle for the shared preferences.
         SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
@@ -5060,8 +5131,8 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
             // Get a handle for the cookie manager.
             CookieManager cookieManager = CookieManager.getInstance();
 
-            // Set the first-party cookie status.
-            cookieManager.setAcceptCookie(currentWebView.getAcceptFirstPartyCookies());
+            // Set the cookie status.
+            cookieManager.setAcceptCookie(currentWebView.getAcceptCookies());
 
             // Update the privacy icons.  `true` redraws the icons in the app bar.
             updatePrivacyIcons(true);
@@ -5236,19 +5307,22 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
                             // Hide the action bar.
                             actionBar.hide();
 
-                            // Check to see if the app bar is normally scrolled.
-                            if (scrollAppBar) {  // The app bar is scrolled when it is displayed.
-                                // Get the swipe refresh layout parameters.
-                                CoordinatorLayout.LayoutParams swipeRefreshLayoutParams = (CoordinatorLayout.LayoutParams) swipeRefreshLayout.getLayoutParams();
-
-                                // Remove the off-screen scrolling layout.
-                                swipeRefreshLayoutParams.setBehavior(null);
-                            } else {  // The app bar is not scrolled when it is displayed.
-                                // Remove the padding from the top of the swipe refresh layout.
-                                swipeRefreshLayout.setPadding(0, 0, 0, 0);
-
-                                // The swipe refresh circle must be moved above the now removed status bar location.
-                                swipeRefreshLayout.setProgressViewOffset(false, -200, defaultProgressViewEndOffset);
+                            // Set layout and scrolling parameters if the app bar is at the top of the screen.
+                            if (!bottomAppBar) {
+                                // Check to see if the app bar is normally scrolled.
+                                if (scrollAppBar) {  // The app bar is scrolled when it is displayed.
+                                    // Get the swipe refresh layout parameters.
+                                    CoordinatorLayout.LayoutParams swipeRefreshLayoutParams = (CoordinatorLayout.LayoutParams) swipeRefreshLayout.getLayoutParams();
+
+                                    // Remove the off-screen scrolling layout.
+                                    swipeRefreshLayoutParams.setBehavior(null);
+                                } else {  // The app bar is not scrolled when it is displayed.
+                                    // Remove the padding from the top of the swipe refresh layout.
+                                    swipeRefreshLayout.setPadding(0, 0, 0, 0);
+
+                                    // The swipe refresh circle must be moved above the now removed status bar location.
+                                    swipeRefreshLayout.setProgressViewOffset(false, -200, defaultProgressViewEndOffset);
+                                }
                             }
                         }
 
@@ -5278,19 +5352,22 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
                             // Show the action bar.
                             actionBar.show();
 
-                            // Check to see if the app bar is normally scrolled.
-                            if (scrollAppBar) {  // The app bar is scrolled when it is displayed.
-                                // Get the swipe refresh layout parameters.
-                                CoordinatorLayout.LayoutParams swipeRefreshLayoutParams = (CoordinatorLayout.LayoutParams) swipeRefreshLayout.getLayoutParams();
-
-                                // Add the off-screen scrolling layout.
-                                swipeRefreshLayoutParams.setBehavior(new AppBarLayout.ScrollingViewBehavior());
-                            } else {  // The app bar is not scrolled when it is displayed.
-                                // The swipe refresh layout must be manually moved below the app bar layout.
-                                swipeRefreshLayout.setPadding(0, appBarHeight, 0, 0);
-
-                                // The swipe to refresh circle doesn't always hide itself completely unless it is moved up 10 pixels.
-                                swipeRefreshLayout.setProgressViewOffset(false, defaultProgressViewStartOffset - 10 + appBarHeight, defaultProgressViewEndOffset + appBarHeight);
+                            // Set layout and scrolling parameters if the app bar is at the top of the screen.
+                            if (!bottomAppBar) {
+                                // Check to see if the app bar is normally scrolled.
+                                if (scrollAppBar) {  // The app bar is scrolled when it is displayed.
+                                    // Get the swipe refresh layout parameters.
+                                    CoordinatorLayout.LayoutParams swipeRefreshLayoutParams = (CoordinatorLayout.LayoutParams) swipeRefreshLayout.getLayoutParams();
+
+                                    // Add the off-screen scrolling layout.
+                                    swipeRefreshLayoutParams.setBehavior(new AppBarLayout.ScrollingViewBehavior());
+                                } else {  // The app bar is not scrolled when it is displayed.
+                                    // The swipe refresh layout must be manually moved below the app bar layout.
+                                    swipeRefreshLayout.setPadding(0, appBarHeight, 0, 0);
+
+                                    // The swipe to refresh circle doesn't always hide itself completely unless it is moved up 10 pixels.
+                                    swipeRefreshLayout.setProgressViewOffset(false, defaultProgressViewStartOffset - 10 + appBarHeight, defaultProgressViewEndOffset + appBarHeight);
+                                }
                             }
                         }
 
@@ -5329,38 +5406,38 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
 
         // Allow the downloading of files.
         nestedScrollWebView.setDownloadListener((String downloadUrl, String userAgent, String contentDisposition, String mimetype, long contentLength) -> {
-            // Define a formatted file size string.
-            String formattedFileSizeString;
-
-            // Process the content length if it contains data.
-            if (contentLength > 0) {  // The content length is greater than 0.
-                // Format the content length as a string.
-                formattedFileSizeString = NumberFormat.getInstance().format(contentLength) + " " + getString(R.string.bytes);
-            } else {  // The content length is not greater than 0.
-                // Set the formatted file size string to be `unknown size`.
-                formattedFileSizeString = getString(R.string.unknown_size);
-            }
+            // Check the download preference.
+            if (downloadWithExternalApp) {  // Download with an external app.
+                downloadUrlWithExternalApp(downloadUrl);
+            } else {  // Handle the download inside of Privacy Browser.
+                // Define a formatted file size string.
+                String formattedFileSizeString;
+
+                // Process the content length if it contains data.
+                if (contentLength > 0) {  // The content length is greater than 0.
+                    // Format the content length as a string.
+                    formattedFileSizeString = NumberFormat.getInstance().format(contentLength) + " " + getString(R.string.bytes);
+                } else {  // The content length is not greater than 0.
+                    // Set the formatted file size string to be `unknown size`.
+                    formattedFileSizeString = getString(R.string.unknown_size);
+                }
+
+                // Get the file name from the content disposition.
+                String fileNameString = PrepareSaveDialog.getFileNameFromHeaders(this, contentDisposition, mimetype, downloadUrl);
 
-            // Get the file name from the content disposition.
-            String fileNameString = PrepareSaveDialog.getFileNameFromHeaders(this, contentDisposition, mimetype, downloadUrl);
+                // Instantiate the save dialog.
+                DialogFragment saveDialogFragment = SaveWebpageDialog.saveWebpage(SaveWebpageDialog.SAVE_URL, downloadUrl, formattedFileSizeString, fileNameString, userAgent,
+                        nestedScrollWebView.getAcceptCookies());
 
-            // Prevent the dialog from displaying if the app window is not visible.
-            // The download listener continues to function even when the WebView is paused.  Attempting to display a dialog in that state leads to a crash.
-            while (!activity.getWindow().isActive()) {
+                // 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.
                 try {
-                    // The window is not active.  Wait 1 second.
-                    wait(1000);
-                } catch (InterruptedException e) {
-                    // Do nothing.
+                    // Show the save dialog.  It must be named `save_dialog` so that the file picker can update the file name.
+                    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)));
                 }
             }
-
-            // Instantiate the save dialog.
-            DialogFragment saveDialogFragment = SaveWebpageDialog.saveWebpage(SaveWebpageDialog.SAVE_URL, downloadUrl, formattedFileSizeString, fileNameString, userAgent,
-                    nestedScrollWebView.getAcceptFirstPartyCookies());
-
-            // Show the save dialog.  It must be named `save_dialog` so that the file picker can update the file name.
-            saveDialogFragment.show(getSupportFragmentManager(), getString(R.string.save_dialog));
         });
 
         // Update the find on page count.
@@ -5389,7 +5466,8 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
         // Update the status of swipe to refresh based on the scroll position of the nested scroll WebView.  Also reinforce full screen browsing mode.
         // On API < 23, `getViewTreeObserver().addOnScrollChangedListener()` must be used, but it is a little bit buggy and appears to get garbage collected from time to time.
         if (Build.VERSION.SDK_INT >= 23) {
-            nestedScrollWebView.setOnScrollChangeListener((view, i, i1, i2, i3) -> {
+            nestedScrollWebView.setOnScrollChangeListener((view, scrollX, scrollY, oldScrollX, oldScrollY) -> {
+                // Set the swipe to refresh status.
                 if (nestedScrollWebView.getSwipeToRefresh()) {
                     // Only enable swipe to refresh if the WebView is scrolled to the top.
                     swipeRefreshLayout.setEnabled(nestedScrollWebView.getScrollY() == 0);
@@ -5398,6 +5476,18 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
                     swipeRefreshLayout.setEnabled(false);
                 }
 
+                //  Set the visibility of the bottom app bar.
+                if (bottomAppBar && scrollAppBar && (Calendar.getInstance().getTimeInMillis() - lastScrollUpdate > 100)) {
+                    if (scrollY - oldScrollY > 25) {  // The WebView was scrolled down.
+                        appBarLayout.setVisibility(View.GONE);
+                    } else if (scrollY - oldScrollY < -25) {  // The WebView was scrolled up.
+                        appBarLayout.setVisibility(View.VISIBLE);
+                    }
+
+                    // Update the last scroll update variable.  This prevents the app bar from flashing on and off at the bottom of the screen.
+                    lastScrollUpdate = Calendar.getInstance().getTimeInMillis();
+                }
+
                 // Reinforce the system UI visibility flags if in full screen browsing mode.
                 // This hides the status and navigation bars, which are displayed if other elements are shown, like dialog boxes, the options menu, or the keyboard.
                 if (inFullScreenBrowsingMode) {
@@ -5421,7 +5511,6 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
                     swipeRefreshLayout.setEnabled(false);
                 }
 
-
                 // Reinforce the system UI visibility flags if in full screen browsing mode.
                 // This hides the status and navigation bars, which are displayed if other elements are shown, like dialog boxes, the options menu, or the keyboard.
                 if (inFullScreenBrowsingMode) {
@@ -5569,65 +5658,8 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
             // Exit full screen video.
             @Override
             public void onHideCustomView() {
-                // Re-enable the screen timeout.
-                fullScreenVideoFrameLayout.setKeepScreenOn(false);
-
-                // Unset the full screen video flag.
-                displayingFullScreenVideo = false;
-
-                // Remove all the views from the full screen video frame layout.
-                fullScreenVideoFrameLayout.removeAllViews();
-
-                // Hide the full screen video frame layout.
-                fullScreenVideoFrameLayout.setVisibility(View.GONE);
-
-                // Enable the sliding drawers.
-                drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
-
-                // Show the main content relative layout.
-                mainContentRelativeLayout.setVisibility(View.VISIBLE);
-
-                // Apply the appropriate full screen mode flags.
-                if (fullScreenBrowsingModeEnabled && inFullScreenBrowsingMode) {  // Privacy Browser is currently in full screen browsing mode.
-                    // Hide the app bar if specified.
-                    if (hideAppBar) {
-                        // Hide the tab linear layout.
-                        tabsLinearLayout.setVisibility(View.GONE);
-
-                        // Hide the action bar.
-                        actionBar.hide();
-                    }
-
-                    // Hide the banner ad in the free flavor.
-                    if (BuildConfig.FLAVOR.contentEquals("free")) {
-                        // Get a handle for the ad view.  This cannot be a class variable because it changes with each ad load.
-                        View adView = findViewById(R.id.adview);
-
-                        // Hide the banner ad.
-                        AdHelper.hideAd(adView);
-                    }
-
-                    /* Hide the system bars.
-                     * SYSTEM_UI_FLAG_FULLSCREEN hides the status bar at the top of the screen.
-                     * SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN makes the root frame layout fill the area that is normally reserved for the status bar.
-                     * SYSTEM_UI_FLAG_HIDE_NAVIGATION hides the navigation bar on the bottom or right of the screen.
-                     * SYSTEM_UI_FLAG_IMMERSIVE_STICKY makes the status and navigation bars translucent and automatically re-hides them after they are shown.
-                     */
-                    rootFrameLayout.setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
-                            View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
-                } else {  // Switch to normal viewing mode.
-                    // Remove the `SYSTEM_UI` flags from the root frame layout.
-                    rootFrameLayout.setSystemUiVisibility(0);
-                }
-
-                // Reload the ad for the free flavor if not in full screen mode.
-                if (BuildConfig.FLAVOR.contentEquals("free") && !inFullScreenBrowsingMode) {
-                    // Get a handle for the ad view.  This cannot be a class variable because it changes with each ad load.
-                    View adView = findViewById(R.id.adview);
-
-                    // Reload the ad.  `getContext()` can be used instead of `getActivity.getApplicationContext()` once the minimum API >= 23.
-                    AdHelper.loadAd(adView, getApplicationContext(), activity, getString(R.string.ad_unit_id));
-                }
+                // Exit the full screen video.
+                exitFullScreenVideo();
             }
 
             // Upload files.
@@ -5856,7 +5888,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
                     String[] ultraListResults = blocklistHelper.checkBlocklist(currentDomain, url, isThirdPartyRequest, ultraList);
 
                     // Process the UltraList results.
-                    if (ultraListResults[0].equals(BlocklistHelper.REQUEST_BLOCKED)) {  // The resource request matched UltraLists's blacklist.
+                    if (ultraListResults[0].equals(BlocklistHelper.REQUEST_BLOCKED)) {  // The resource request matched UltraList's blacklist.
                         // Add the result to the resource requests.
                         nestedScrollWebView.addResourceRequest(new String[] {ultraListResults[0], ultraListResults[1], ultraListResults[2], ultraListResults[3], ultraListResults[4], ultraListResults[5]});
 
@@ -6110,25 +6142,25 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
 
             @Override
             public void onPageStarted(WebView view, String url, Bitmap favicon) {
-                // Get the preferences.
-                boolean scrollAppBar = sharedPreferences.getBoolean("scroll_app_bar", true);
-
-                // Set the top padding of the swipe refresh layout according to the app bar scrolling preference.  This can't be done in `appAppSettings()` because the app bar is not yet populated there.
-                if (scrollAppBar || (inFullScreenBrowsingMode && hideAppBar)) {
-                    // No padding is needed because it will automatically be placed below the app bar layout due to the scrolling layout behavior.
-                    swipeRefreshLayout.setPadding(0, 0, 0, 0);
-
-                    // The swipe to refresh circle doesn't always hide itself completely unless it is moved up 10 pixels.
-                    swipeRefreshLayout.setProgressViewOffset(false, defaultProgressViewStartOffset - 10, defaultProgressViewEndOffset);
-                } else {
-                    // Get the app bar layout height.  This can't be done in `applyAppSettings()` because the app bar is not yet populated there.
-                    appBarHeight = appBarLayout.getHeight();
-
-                    // The swipe refresh layout must be manually moved below the app bar layout.
-                    swipeRefreshLayout.setPadding(0, appBarHeight, 0, 0);
-
-                    // The swipe to refresh circle doesn't always hide itself completely unless it is moved up 10 pixels.
-                    swipeRefreshLayout.setProgressViewOffset(false, defaultProgressViewStartOffset - 10 + appBarHeight, defaultProgressViewEndOffset + appBarHeight);
+                // Set the padding and layout settings if the app bar is at the top of the screen.
+                if (!bottomAppBar) {
+                    // Set the top padding of the swipe refresh layout according to the app bar scrolling preference.  This can't be done in `appAppSettings()` because the app bar is not yet populated there.
+                    if (scrollAppBar || (inFullScreenBrowsingMode && hideAppBar)) {
+                        // No padding is needed because it will automatically be placed below the app bar layout due to the scrolling layout behavior.
+                        swipeRefreshLayout.setPadding(0, 0, 0, 0);
+
+                        // The swipe to refresh circle doesn't always hide itself completely unless it is moved up 10 pixels.
+                        swipeRefreshLayout.setProgressViewOffset(false, defaultProgressViewStartOffset - 10, defaultProgressViewEndOffset);
+                    } else {
+                        // Get the app bar layout height.  This can't be done in `applyAppSettings()` because the app bar is not yet populated there.
+                        appBarHeight = appBarLayout.getHeight();
+
+                        // The swipe refresh layout must be manually moved below the app bar layout.
+                        swipeRefreshLayout.setPadding(0, appBarHeight, 0, 0);
+
+                        // The swipe to refresh circle doesn't always hide itself completely unless it is moved up 10 pixels.
+                        swipeRefreshLayout.setProgressViewOffset(false, defaultProgressViewStartOffset - 10 + appBarHeight, defaultProgressViewEndOffset + appBarHeight);
+                    }
                 }
 
                 // Reset the list of resource requests.
@@ -6145,7 +6177,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
                     // Display the formatted URL text.
                     urlEditText.setText(url);
 
-                    // Apply text highlighting to `urlTextBox`.
+                    // Apply text highlighting to the URL text box.
                     highlightUrlText();
 
                     // Hide the keyboard.
@@ -6187,7 +6219,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
             @Override
             public void onPageFinished(WebView view, String url) {
                 // Flush any cookies to persistent storage.  The cookie manager has become very lazy about flushing cookies in recent versions.
-                if (nestedScrollWebView.getAcceptFirstPartyCookies() && Build.VERSION.SDK_INT >= 21) {
+                if (nestedScrollWebView.getAcceptCookies() && Build.VERSION.SDK_INT >= 21) {
                     CookieManager.getInstance().flush();
                 }
 
@@ -6356,22 +6388,17 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
                     // Store the SSL error handler.
                     nestedScrollWebView.setSslErrorHandler(handler);
 
-                    // Prevent the dialog from displaying if the app window is not visible.
-                    // The SSL error handler continues to function even when the WebView is paused.  Attempting to display a dialog in that state leads to a crash.
-                    while (!activity.getWindow().isActive()) {
-                        try {
-                            // The window is not active.  Wait 1 second.
-                            wait(1000);
-                        } catch (InterruptedException e) {
-                            // Do nothing.
-                        }
-                    }
-
                     // Instantiate an SSL certificate error alert dialog.
                     DialogFragment sslCertificateErrorDialogFragment = SslCertificateErrorDialog.displayDialog(error, nestedScrollWebView.getWebViewFragmentId());
 
-                    // Show the SSL certificate error dialog.
-                    sslCertificateErrorDialogFragment.show(getSupportFragmentManager(), getString(R.string.ssl_certificate_error));
+                    // Try to show the dialog.  The SSL error handler continues to function even when the WebView is paused.  Attempting to display a dialog in that state leads to a crash.
+                    try {
+                        // Show the SSL certificate error dialog.
+                        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)));
+                    }
                 }
             }
         });