]> gitweb.stoutner.com Git - PrivacyBrowserAndroid.git/blobdiff - app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.kt
Don't populate the current domain in the new domain settings dialog. https://redmine...
[PrivacyBrowserAndroid.git] / app / src / main / java / com / stoutner / privacybrowser / activities / MainWebViewActivity.kt
index ffa89265081f2846a831cb6b55d8e22b981b1254..0d9755f1f21d2621716c6f678ad5d3da6f025332 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2015-2023 Soren Stoutner <soren@stoutner.com>.
+ * Copyright 2015-2024 Soren Stoutner <soren@stoutner.com>.
  *
  * Download cookie code contributed 2017 Hendrik Knackstedt.  Copyright assigned to Soren Stoutner <soren@stoutner.com>.
  *
@@ -93,17 +93,19 @@ import android.widget.TextView
 import androidx.activity.OnBackPressedCallback
 import androidx.activity.result.contract.ActivityResultContracts
 import androidx.appcompat.app.ActionBar
-import androidx.appcompat.app.ActionBarDrawerToggle
 import androidx.appcompat.app.AppCompatActivity
 import androidx.appcompat.app.AppCompatDelegate
 import androidx.appcompat.content.res.AppCompatResources
 import androidx.appcompat.widget.Toolbar
 import androidx.coordinatorlayout.widget.CoordinatorLayout
+import androidx.core.content.ContextCompat
 import androidx.core.view.GravityCompat
 import androidx.cursoradapter.widget.CursorAdapter
 import androidx.drawerlayout.widget.DrawerLayout
 import androidx.fragment.app.DialogFragment
 import androidx.preference.PreferenceManager
+import androidx.recyclerview.widget.LinearLayoutManager
+import androidx.recyclerview.widget.RecyclerView
 import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
 import androidx.viewpager2.widget.ViewPager2
 import androidx.webkit.WebSettingsCompat
@@ -280,6 +282,8 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
     private lateinit var navigationForwardMenuItem: MenuItem
     private lateinit var navigationHistoryMenuItem: MenuItem
     private lateinit var navigationRequestsMenuItem: MenuItem
+    private lateinit var navigationScrollToBottomMenuItem: MenuItem
+    private lateinit var navigationView: NavigationView
     private lateinit var optionsAddOrEditDomainMenuItem: MenuItem
     private lateinit var optionsBlockAllThirdPartyRequestsMenuItem: MenuItem
     private lateinit var optionsClearCookiesMenuItem: MenuItem
@@ -315,12 +319,12 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
     private lateinit var optionsUserAgentFirefoxOnAndroidMenuItem: MenuItem
     private lateinit var optionsUserAgentFirefoxOnLinuxMenuItem: MenuItem
     private lateinit var optionsUserAgentFirefoxOnWindowsMenuItem: MenuItem
-    private lateinit var optionsUserAgentInternetExplorerOnWindowsMenuItem: MenuItem
     private lateinit var optionsUserAgentMenuItem: MenuItem
     private lateinit var optionsUserAgentPrivacyBrowserMenuItem: MenuItem
     private lateinit var optionsUserAgentSafariOnIosMenuItem: MenuItem
     private lateinit var optionsUserAgentSafariOnMacosMenuItem: MenuItem
     private lateinit var optionsUserAgentWebViewDefaultMenuItem: MenuItem
+    private lateinit var optionsViewSourceMenuItem: MenuItem
     private lateinit var optionsWideViewportMenuItem: MenuItem
     private lateinit var proxyHelper: ProxyHelper
     private lateinit var redColorSpan: ForegroundColorSpan
@@ -339,10 +343,11 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
     private lateinit var urlEditText: EditText
     private lateinit var urlRelativeLayout: RelativeLayout
     private lateinit var userAgentDataArray: Array<String>
-    private lateinit var userAgentNamesArray: ArrayAdapter<CharSequence>
+    private lateinit var userAgentNamesArray: Array<String>
+    private lateinit var userAgentDataArrayAdapter: ArrayAdapter<CharSequence>
+    private lateinit var userAgentNamesArrayAdapter: ArrayAdapter<CharSequence>
 
     // Define the class variables.
-    private var actionBarDrawerToggle: ActionBarDrawerToggle? = null
     private var appBarHeight = 0
     private var bookmarksCursor: Cursor? = null
     private var bookmarksDatabaseHelper: BookmarksDatabaseHelper? = null
@@ -370,10 +375,11 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
     private var domainsDatabaseHelper: DomainsDatabaseHelper? = null
     private var downloadWithExternalApp = false
     private var fullScreenBrowsingModeEnabled = false
-    private var hideAppBar = false
+    private var hideAppBar = true
     private var inFullScreenBrowsingMode = false
     private var incognitoModeEnabled = false
     private var loadingNewIntent = false
+    private var navigationDrawerFirstView = true
     private var objectAnimator = ObjectAnimator()
     private var optionsMenu: Menu? = null
     private var orbotStatusBroadcastReceiver: BroadcastReceiver? = null
@@ -516,6 +522,15 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
         val allowScreenshots = sharedPreferences.getBoolean(getString(R.string.allow_screenshots_key), false)
         bottomAppBar = sharedPreferences.getBoolean(getString(R.string.bottom_app_bar_key), false)
         displayAdditionalAppBarIcons = sharedPreferences.getBoolean(getString(R.string.display_additional_app_bar_icons_key), false)
+        val displayUnderCutouts = sharedPreferences.getBoolean(getString(R.string.display_under_cutouts_key), false)
+
+        // Display under cutouts if specified.  This must be done here as it doesn't appear to work correctly if handled after the app is fully initialized.
+        if (displayUnderCutouts) {
+            if (Build.VERSION.SDK_INT >= 30)
+                window.attributes.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
+            else if (Build.VERSION.SDK_INT >= 28)
+                window.attributes.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
+        }
 
         // Get the theme entry values string array.
         val appThemeEntryValuesStringArray = resources.getStringArray(R.array.app_theme_entry_values)
@@ -587,7 +602,7 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
             tabLayout = findViewById(R.id.tablayout)
             swipeRefreshLayout = findViewById(R.id.swiperefreshlayout)
             webViewViewPager2 = findViewById(R.id.webview_viewpager2)
-            val navigationView = findViewById<NavigationView>(R.id.navigationview)
+            navigationView = findViewById(R.id.navigationview)
             bookmarksListView = findViewById(R.id.bookmarks_drawer_listview)
             bookmarksTitleTextView = findViewById(R.id.bookmarks_title_textview)
             bookmarksDrawerPinnedImageView = findViewById(R.id.bookmarks_drawer_pinned_imageview)
@@ -599,6 +614,7 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
             // Get handles for the navigation menu items.
             navigationBackMenuItem = navigationMenu.findItem(R.id.back)
             navigationForwardMenuItem = navigationMenu.findItem(R.id.forward)
+            navigationScrollToBottomMenuItem = navigationMenu.findItem(R.id.scroll_to_bottom)
             navigationHistoryMenuItem = navigationMenu.findItem(R.id.history)
             navigationRequestsMenuItem = navigationMenu.findItem(R.id.requests)
 
@@ -621,9 +637,6 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
             urlRelativeLayout = findViewById(R.id.url_relativelayout)
             urlEditText = findViewById(R.id.url_edittext)
 
-            // Create the hamburger icon at the start of the AppBar.
-            actionBarDrawerToggle = ActionBarDrawerToggle(this, drawerLayout, toolbar, R.string.open_navigation_drawer, R.string.close_navigation_drawer)
-
             // Initially disable the sliding drawers.  They will be enabled once the filter lists are loaded.
             drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED)
 
@@ -631,9 +644,9 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
             drawerLayout.visibility = View.GONE
 
             // Initialize the WebView state adapter.
-            webViewStateAdapter = WebViewStateAdapter(this)
+            webViewStateAdapter = WebViewStateAdapter(this, bottomAppBar)
 
-            // Set the pager adapter on the web view pager.
+            // Set the WebView pager adapter.
             webViewViewPager2.adapter = webViewStateAdapter
 
             // Store up to 100 tabs in memory.
@@ -677,14 +690,31 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
                         // Get the current web back forward list.
                         val webBackForwardList = currentWebView!!.copyBackForwardList()
 
-                        // Get the previous entry URL.
+                        // Get the previous entry data.
                         val previousUrl = webBackForwardList.getItemAtIndex(webBackForwardList.currentIndex - 1).url
+                        val previousFavoriteIcon = webBackForwardList.getItemAtIndex(webBackForwardList.currentIndex - 1).favicon
 
                         // Apply the domain settings.
                         applyDomainSettings(currentWebView!!, previousUrl, resetTab = false, reloadWebsite = false, loadUrl = false)
 
+                        // Get the current tab.
+                        val tab = tabLayout.getTabAt(tabLayout.selectedTabPosition)!!
+
+                        // Get the custom view from the tab.
+                        val tabView = tab.customView!!
+
+                        // Get the favorite icon image view from the tab.
+                        val tabFavoriteIconImageView = tabView.findViewById<ImageView>(R.id.favorite_icon_imageview)
+
+                        // Set the previous favorite icon if it isn't null.
+                        if (previousFavoriteIcon != null)
+                            tabFavoriteIconImageView.setImageBitmap(Bitmap.createScaledBitmap(previousFavoriteIcon, 64, 64, true))
+
                         // Go back.
                         currentWebView!!.goBack()
+
+                        // Update the URL edit text after a delay.
+                        updateUrlEditTextAfterDelay()
                     } else {  // Close the current tab.
                         // A view is required because the method is also called by an XML `onClick`.
                         closeTab(null)
@@ -703,19 +733,18 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
         }
     }
 
-    public override fun onPostCreate(savedInstanceState: Bundle?) {
-        // Run the default commands.
-        super.onPostCreate(savedInstanceState)
-
-        // Sync the state of the DrawerToggle after the default `onRestoreInstanceState()` has finished.  This creates the navigation drawer icon.
-        // If the app is restarting to change the app theme the action bar drawer toggle will not yet be populated.
-        actionBarDrawerToggle?.syncState()
-    }
-
     override fun onNewIntent(intent: Intent) {
         // Run the default commands.
         super.onNewIntent(intent)
 
+        // Close the navigation drawer if it is open.
+        if (drawerLayout.isDrawerVisible(GravityCompat.START))
+            drawerLayout.closeDrawer(GravityCompat.START)
+
+        // Close the bookmarks drawer if it is open.
+        if (drawerLayout.isDrawerVisible(GravityCompat.END))
+            drawerLayout.closeDrawer(GravityCompat.END)
+
         // Get the information from the intent.
         val intentAction = intent.action
         val intentUriData = intent.data
@@ -758,26 +787,13 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
                     loadingNewIntent = true
 
                     // Add a new tab.
-                    addNewTab(url!!, true)
+                    addNewPage(url!!, adjacent = false, moveToTab = true)
                 } else {  // Load the URL in the current tab.
                     // Make it so.
                     loadUrl(currentWebView!!, url!!)
                 }
-
-                // Close the navigation drawer if it is open.
-                if (drawerLayout.isDrawerVisible(GravityCompat.START))
-                    drawerLayout.closeDrawer(GravityCompat.START)
-
-                // Close the bookmarks drawer if it is open.
-                if (drawerLayout.isDrawerVisible(GravityCompat.END))
-                    drawerLayout.closeDrawer(GravityCompat.END)
             }
         } else {  // The app has been restarted.
-            // If the new intent will open a new tab, set the saved tab position to be the size of the saved state array list.
-            // The tab position is 0 based, meaning the at the new tab will be the tab position that is restored.
-            if ((intentUriData != null) || (intentStringExtra != null) || isWebSearch)
-                savedTabPosition = savedStateArrayList!!.size
-
             // Replace the intent that started the app with this one.  This will load the tab after the others have been restored.
             setIntent(intent)
         }
@@ -1003,17 +1019,23 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
         // Run the default commands.
         super.onConfigurationChanged(newConfig)
 
+        // Reset the navigation drawer first view flag.
+        navigationDrawerFirstView = true
+
         // Get the current page.
         val currentPage = webViewViewPager2.currentItem
 
         // Toggle the pages if there is more than one so that the view pager will recalculate their size.
         if (currentPage > 0) {
-            // Switch to the previous page.
-            webViewViewPager2.currentItem = (currentPage - 1)
+            // Switch to the previous page after 25 milliseconds.
+            webViewViewPager2.postDelayed ({ webViewViewPager2.currentItem = (currentPage - 1) }, 25)
 
-            // Switch back to the current page after the view pager has quiesced.
-            webViewViewPager2.post { webViewViewPager2.currentItem = currentPage }
+            // Switch back to the current page after the view pager has quiesced (which we are deciding should be 25 milliseconds).
+            webViewViewPager2.postDelayed ({ webViewViewPager2.currentItem = currentPage }, 25)
         }
+
+        // Scroll to the current tab position after 25 milliseconds.
+        tabLayout.postDelayed ({ tabLayout.setScrollPosition(currentPage, 0F, false, false) }, 25)
     }
 
     override fun onCreateOptionsMenu(menu: Menu): Boolean {
@@ -1055,7 +1077,6 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
         optionsUserAgentFirefoxOnWindowsMenuItem = menu.findItem(R.id.user_agent_firefox_on_windows)
         optionsUserAgentChromeOnWindowsMenuItem = menu.findItem(R.id.user_agent_chrome_on_windows)
         optionsUserAgentEdgeOnWindowsMenuItem = menu.findItem(R.id.user_agent_edge_on_windows)
-        optionsUserAgentInternetExplorerOnWindowsMenuItem = menu.findItem(R.id.user_agent_internet_explorer_on_windows)
         optionsUserAgentSafariOnMacosMenuItem = menu.findItem(R.id.user_agent_safari_on_macos)
         optionsUserAgentCustomMenuItem = menu.findItem(R.id.user_agent_custom)
         optionsSwipeToRefreshMenuItem = menu.findItem(R.id.swipe_to_refresh)
@@ -1063,6 +1084,7 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
         optionsDisplayImagesMenuItem = menu.findItem(R.id.display_images)
         optionsDarkWebViewMenuItem = menu.findItem(R.id.dark_webview)
         optionsFontSizeMenuItem = menu.findItem(R.id.font_size)
+        optionsViewSourceMenuItem = menu.findItem(R.id.view_source)
         optionsAddOrEditDomainMenuItem = menu.findItem(R.id.add_or_edit_domain)
 
         // Set the initial status of the privacy icons.  `false` does not call `invalidateOptionsMenu` as the last step.
@@ -1137,7 +1159,7 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
             optionsWideViewportMenuItem.isChecked = currentWebView!!.settings.useWideViewPort
             optionsDisplayImagesMenuItem.isChecked = currentWebView!!.settings.loadsImagesAutomatically
 
-            // Initialize the display names for the filter lists with the number of blocked requests.
+            // Set the display names for the filter lists with the number of blocked requests.
             optionsFilterListsMenuItem.title = getString(R.string.filterlists) + " - " + currentWebView!!.getRequestsCount(BLOCKED_REQUESTS)
             optionsEasyListMenuItem.title = currentWebView!!.getRequestsCount(EASYLIST).toString() + " - " + getString(R.string.easylist)
             optionsEasyPrivacyMenuItem.title = currentWebView!!.getRequestsCount(EASYPRIVACY).toString() + " - " + getString(R.string.easyprivacy)
@@ -1159,6 +1181,12 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
             // Set the checkbox status for dark WebView if algorithmic darkening is supported.
             if (WebViewFeature.isFeatureSupported(WebViewFeature.ALGORITHMIC_DARKENING))
                 optionsDarkWebViewMenuItem.isChecked = WebSettingsCompat.isAlgorithmicDarkeningAllowed(currentWebView!!.settings)
+
+            // Set the view source title according to the current URL.
+            if (currentWebView!!.currentUrl.startsWith("view-source:"))
+                optionsViewSourceMenuItem.title = getString(R.string.view_rendered_website)
+            else
+                optionsViewSourceMenuItem.title = getString(R.string.view_source)
         }
 
         // Set the cookies menu item checked status.
@@ -1322,15 +1350,7 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
                 optionsUserAgentEdgeOnWindowsMenuItem.isChecked = true
             }
 
-            resources.getStringArray(R.array.user_agent_data)[10] -> {  // Internet Explorer on Windows.
-                // Update the user agent menu item title.
-                optionsUserAgentMenuItem.title = getString(R.string.options_user_agent) + " - " + getString(R.string.user_agent_internet_explorer_on_windows)
-
-                // Select the Internet on Windows radio box.
-                optionsUserAgentInternetExplorerOnWindowsMenuItem.isChecked = true
-            }
-
-            resources.getStringArray(R.array.user_agent_data)[11] -> {  // Safari on macOS.
+            resources.getStringArray(R.array.user_agent_data)[10] -> {  // Safari on macOS.
                 // Update the user agent menu item title.
                 optionsUserAgentMenuItem.title = getString(R.string.options_user_agent) + " - " + getString(R.string.user_agent_safari_on_macos)
 
@@ -1830,20 +1850,9 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
                 true
             }
 
-            R.id.user_agent_internet_explorer_on_windows -> {  // User Agent - Internet Explorer on Windows.
-                // Update the user agent.
-                currentWebView!!.settings.userAgentString = resources.getStringArray(R.array.user_agent_data)[10]
-
-                // Reload the current WebView.
-                currentWebView!!.reload()
-
-                // Consume the event.
-                true
-            }
-
             R.id.user_agent_safari_on_macos -> {  // User Agent - Safari on macOS.
                 // Update the user agent.
-                currentWebView!!.settings.userAgentString = resources.getStringArray(R.array.user_agent_data)[11]
+                currentWebView!!.settings.userAgentString = resources.getStringArray(R.array.user_agent_data)[10]
 
                 // Reload the current WebView.
                 currentWebView!!.reload()
@@ -1976,8 +1985,8 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
             }
 
             R.id.save_archive -> {
-                // Open the file picker with a default file name built from the current domain name.
-                saveWebpageArchiveActivityResultLauncher.launch(currentWebView!!.currentDomainName + ".mht")
+                // Open the file picker with a default file name built from the website title.
+                saveWebpageArchiveActivityResultLauncher.launch(currentWebView!!.title + ".mht")
 
                 // Consume the event.
                 true
@@ -2003,15 +2012,29 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
             }
 
             R.id.view_source -> {  // View source.
-                // Create an intent to launch the view source activity.
-                val viewSourceIntent = Intent(this, ViewSourceActivity::class.java)
+                // Open a new tab according to the current URL.
+                if (currentWebView!!.currentUrl.startsWith("view-source:")) {  // The source is currently viewed.
+                    // Open the rendered website in a new tab.
+                    addNewPage(currentWebView!!.currentUrl.substring(12, currentWebView!!.currentUrl.length), true, moveToTab = true)
+                } else {  // The rendered website is currently viewed.
+                    // Open the source in a new tab.
+                    addNewPage("view-source:${currentWebView!!.currentUrl}", adjacent = true, moveToTab = true)
+                }
+
+                // Consume the event.
+                true
+            }
+
+            R.id.view_headers -> {  // View headers.
+                // Create an intent to launch the view headers activity.
+                val viewHeadersIntent = Intent(this, ViewHeadersActivity::class.java)
 
                 // Add the variables to the intent.
-                viewSourceIntent.putExtra(CURRENT_URL, currentWebView!!.url)
-                viewSourceIntent.putExtra(USER_AGENT, currentWebView!!.settings.userAgentString)
+                viewHeadersIntent.putExtra(CURRENT_URL, currentWebView!!.url)
+                viewHeadersIntent.putExtra(USER_AGENT, currentWebView!!.settings.userAgentString)
 
                 // Make it so.
-                startActivity(viewSourceIntent)
+                startActivity(viewHeadersIntent)
 
                 // Consume the event.
                 true
@@ -2080,7 +2103,7 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
             }
 
             R.id.add_or_edit_domain -> {  // Add or edit domain.
-                // Reapply the domain settings on returning to `MainWebViewActivity`.
+                // Reapply the domain settings on returning to the main WebView activity.
                 reapplyDomainSettingsOnRestart = true
 
                 // Check if domain settings are currently applied.
@@ -2091,7 +2114,6 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
                     // Add the extra information to the intent.
                     domainsIntent.putExtra(LOAD_DOMAIN, currentWebView!!.domainSettingsDatabaseId)
                     domainsIntent.putExtra(CLOSE_ON_BACK, true)
-                    domainsIntent.putExtra(CURRENT_URL, currentWebView!!.url)
                     domainsIntent.putExtra(CURRENT_IP_ADDRESSES, currentWebView!!.currentIpAddresses)
 
                     // Get the current certificate.
@@ -2129,8 +2151,118 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
                     // Get the current domain from the URI.  Use an empty string if it is null.
                     val currentDomain = currentUri.host?: ""
 
+                    // Get the current settings status.
+                    val javaScriptInt = calculateSettingsInt(currentWebView!!.settings.javaScriptEnabled, sharedPreferences.getBoolean(getString(R.string.javascript_key), false))
+                    val cookiesInt = calculateSettingsInt(currentWebView!!.acceptCookies, sharedPreferences.getBoolean(getString(R.string.cookies_key), false))
+                    val domStorageInt = calculateSettingsInt(currentWebView!!.settings.domStorageEnabled, sharedPreferences.getBoolean(getString(R.string.dom_storage_key), false))
+                    val easyListInt = calculateSettingsInt(currentWebView!!.easyListEnabled, sharedPreferences.getBoolean(getString(R.string.easylist_key), true))
+                    val easyPrivacyInt = calculateSettingsInt(currentWebView!!.easyPrivacyEnabled, sharedPreferences.getBoolean(getString(R.string.easyprivacy_key), true))
+                    val fanboysAnnoyanceListInt = calculateSettingsInt(currentWebView!!.fanboysAnnoyanceListEnabled, sharedPreferences.getBoolean(getString(R.string.fanboys_annoyance_list_key), true))
+                    val fanboysSocialBlockingListInt = calculateSettingsInt(currentWebView!!.fanboysSocialBlockingListEnabled, sharedPreferences.getBoolean(getString(R.string.fanboys_social_blocking_list_key), true))
+                    val ultraListInt = calculateSettingsInt(currentWebView!!.ultraListEnabled, sharedPreferences.getBoolean(getString(R.string.ultralist_key), true))
+                    val ultraPrivacyInt = calculateSettingsInt(currentWebView!!.ultraPrivacyEnabled, sharedPreferences.getBoolean(getString(R.string.ultraprivacy_key), true))
+                    val blockAllThirdPartyRequestsInt = calculateSettingsInt(currentWebView!!.blockAllThirdPartyRequests, sharedPreferences.getBoolean(getString(R.string.block_all_third_party_requests_key), true))
+                    val swipeToRefreshInt = calculateSettingsInt(currentWebView!!.swipeToRefresh, sharedPreferences.getBoolean(getString(R.string.swipe_to_refresh_key), true))
+                    val wideViewportInt = calculateSettingsInt(currentWebView!!.settings.useWideViewPort, sharedPreferences.getBoolean(getString(R.string.wide_viewport_key), true))
+                    val displayImagesInt = calculateSettingsInt(currentWebView!!.settings.loadsImagesAutomatically, sharedPreferences.getBoolean(getString(R.string.display_webpage_images_key), true))
+
+                    // Initialize the form data int.
+                    var formDataInt = SYSTEM_DEFAULT
+
+                    // Set the form data int, which can be removed once the minimum API >= 26.
+                    @Suppress("DEPRECATION")
+                    if (Build.VERSION.SDK_INT < 26) {
+                        // Get the form data status.
+                        val formDataEnabled = currentWebView!!.settings.saveFormData
+
+                        // Calculate the form data Int.
+                        formDataInt = calculateSettingsInt(formDataEnabled, sharedPreferences.getBoolean(getString(R.string.save_form_data_key), false))
+                    }
+
+                    // Get the current user agent string.
+                    val currentUserAgentString = currentWebView!!.settings.userAgentString
+
+                    // Get the user agent string array position.
+                    val userAgentStringArrayPosition = userAgentDataArrayAdapter.getPosition(currentUserAgentString)
+
+                    // Set the user agent name.
+                    val userAgentName = if ((userAgentStringArrayPosition >= 0) && (defaultUserAgentName == userAgentNamesArray[userAgentStringArrayPosition])) {  // The system default user agent is in use.
+                        getString(R.string.system_default_user_agent)
+                    } else {  // An on-the-fly user agent is being used (or the WebView default user agent is applied).
+                        when (userAgentStringArrayPosition) {
+                            UNRECOGNIZED_USER_AGENT -> { // The user agent is unrecognized.
+                                if (currentUserAgentString == webViewDefaultUserAgent) {  // The WebView default user agent is being used.
+                                    if (defaultUserAgentName == getString(R.string.webview_default)) {  // The WebView default user agent is the system default.
+                                        // Set the user agent name to be the system default.
+                                        getString(R.string.system_default_user_agent)
+                                    } else {  // The WebView default user agent is set as an on-the-fly setting.
+                                        // Set the default user agent name.
+                                        getString(R.string.webview_default)
+                                    }
+                                } else {  // A custom user agent is being used.
+                                    if (defaultUserAgentName == getString(R.string.custom_user_agent_non_translatable)) {  // The system custom user agent is in use.
+                                        // Set the user agent name to be the system default.
+                                        getString(R.string.system_default_user_agent)
+                                    } else {  // An on-the-fly custom user agent is in use.
+                                        // Store the user agent as currently applied.
+                                        currentUserAgentString
+                                    }
+                                }
+                            }
+
+                            else ->  // Store the standard user agent name.
+                                userAgentNamesArray[userAgentStringArrayPosition]
+                        }
+                    }
+
+                    // Get the current text zoom integer.
+                    val textZoomInt = currentWebView!!.settings.textZoom
+
+                    // Set the font size integer.
+                    val fontSizeInt = if (textZoomInt == defaultFontSizeString.toInt())  // The current system default is used, which is encoded as a zoom of `0`.
+                        SYSTEM_DEFAULT
+                    else  // A custom font size is used.
+                        textZoomInt
+
+                    // Get the current WebView dark theme status.
+                    val webViewDarkThemeCurrentlyEnabled = if (WebViewFeature.isFeatureSupported(WebViewFeature.ALGORITHMIC_DARKENING))  // Algorithmic darkening is supported.
+                        WebSettingsCompat.isAlgorithmicDarkeningAllowed(currentWebView!!.settings)
+                    else  // Algorithmic darkening is not supported.
+                        false
+
+                    // Get the default WebView dark theme setting.
+                    val defaultWebViewDarkThemeEnabled = if (WebViewFeature.isFeatureSupported(WebViewFeature.ALGORITHMIC_DARKENING)) {  // Algorithmic darkening is supported.
+                        when (defaultWebViewTheme) {
+                            webViewThemeEntryValuesStringArray[1] ->  // The dark theme is disabled by default.
+                                false
+
+                            webViewThemeEntryValuesStringArray[2] ->  // The dark theme is enabled by default.
+                                true
+
+                            else -> {  // The system default theme is selected.
+                                // Get the current app theme status.
+                                val currentAppThemeStatus = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
+
+                                // Check if the current app theme is dark.
+                                currentAppThemeStatus == Configuration.UI_MODE_NIGHT_YES
+                            }
+                        }
+                    } else {  // Algorithmic darkening is not supported.
+                        false
+                    }
+
+                    // Set the WebView theme int.
+                    val webViewThemeInt = if (webViewDarkThemeCurrentlyEnabled == defaultWebViewDarkThemeEnabled)  // The current WebView theme matches the default.
+                        SYSTEM_DEFAULT
+                    else if (webViewDarkThemeCurrentlyEnabled)  // The current WebView theme is dark and that is not the default.
+                        DARK_THEME
+                    else  // The current WebView theme is light and that is not the default.
+                        LIGHT_THEME
+
                     // Create the domain and store the database ID.
-                    val newDomainDatabaseId = domainsDatabaseHelper!!.addDomain(currentDomain)
+                    val newDomainDatabaseId = domainsDatabaseHelper!!.addDomain(currentDomain, javaScriptInt, cookiesInt, domStorageInt, formDataInt, userAgentName, easyListInt, easyPrivacyInt,
+                                                                                fanboysAnnoyanceListInt, fanboysSocialBlockingListInt, ultraListInt, ultraPrivacyInt, blockAllThirdPartyRequestsInt, fontSizeInt,
+                                                                                swipeToRefreshInt, webViewThemeInt, wideViewportInt, displayImagesInt)
 
                     // Create an intent to launch the domains activity.
                     val domainsIntent = Intent(this, DomainsActivity::class.java)
@@ -2138,7 +2270,6 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
                     // Add the extra information to the intent.
                     domainsIntent.putExtra(LOAD_DOMAIN, newDomainDatabaseId)
                     domainsIntent.putExtra(CLOSE_ON_BACK, true)
-                    domainsIntent.putExtra(CURRENT_URL, currentWebView!!.url)
                     domainsIntent.putExtra(CURRENT_IP_ADDRESSES, currentWebView!!.currentIpAddresses)
 
                     // Get the current certificate.
@@ -2201,14 +2332,30 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
                     // Get the current web back forward list.
                     val webBackForwardList = currentWebView!!.copyBackForwardList()
 
-                    // Get the previous entry URL.
+                    // Get the previous entry data.
                     val previousUrl = webBackForwardList.getItemAtIndex(webBackForwardList.currentIndex - 1).url
+                    val previousFavoriteIcon = webBackForwardList.getItemAtIndex(webBackForwardList.currentIndex - 1).favicon!!
 
                     // Apply the domain settings.
                     applyDomainSettings(currentWebView!!, previousUrl, resetTab = false, reloadWebsite = false, loadUrl = false)
 
+                    // Get the current tab.
+                    val tab = tabLayout.getTabAt(tabLayout.selectedTabPosition)!!
+
+                    // Get the custom view from the tab.
+                    val tabView = tab.customView!!
+
+                    // Get the favorite icon image view from the tab.
+                    val tabFavoriteIconImageView = tabView.findViewById<ImageView>(R.id.favorite_icon_imageview)
+
+                    // Set the previous favorite icon.
+                    tabFavoriteIconImageView.setImageBitmap(Bitmap.createScaledBitmap(previousFavoriteIcon, 64, 64, true))
+
                     // Load the previous website in the history.
                     currentWebView!!.goBack()
+
+                    // Update the URL edit text after a delay.
+                    updateUrlEditTextAfterDelay()
                 }
             }
 
@@ -2218,14 +2365,39 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
                     // Get the current web back forward list.
                     val webBackForwardList = currentWebView!!.copyBackForwardList()
 
-                    // Get the next entry URL.
+                    // Get the next entry data.
                     val nextUrl = webBackForwardList.getItemAtIndex(webBackForwardList.currentIndex + 1).url
+                    val nextFavoriteIcon = webBackForwardList.getItemAtIndex(webBackForwardList.currentIndex + 1).favicon!!
 
                     // Apply the domain settings.
                     applyDomainSettings(currentWebView!!, nextUrl, resetTab = false, reloadWebsite = false, loadUrl = false)
 
+                    // Get the current tab.
+                    val tab = tabLayout.getTabAt(tabLayout.selectedTabPosition)!!
+
+                    // Get the custom view from the tab.
+                    val tabView = tab.customView!!
+
+                    // Get the favorite icon image view from the tab.
+                    val tabFavoriteIconImageView = tabView.findViewById<ImageView>(R.id.favorite_icon_imageview)
+
+                    // Set the next favorite icon.
+                    tabFavoriteIconImageView.setImageBitmap(Bitmap.createScaledBitmap(nextFavoriteIcon, 64, 64, true))
+
                     // Load the next website in the history.
                     currentWebView!!.goForward()
+
+                    // Update the URL edit text after a delay.
+                    updateUrlEditTextAfterDelay()
+                }
+            }
+
+            R.id.scroll_to_bottom -> {  // Scroll to Bottom.
+                // Check if the WebView is scrolled to the top.
+                if (currentWebView!!.scrollY == 0) {  // The WebView is at the top; scroll to the bottom.  Using a large Y number is more efficient than trying to calculate the exact WebView length.
+                    currentWebView!!.scrollTo(0, 1_000_000_000)
+                } else {  // The WebView is not at the top; scroll to the top.
+                    currentWebView!!.scrollTo(0, 0)
                 }
             }
 
@@ -2314,7 +2486,6 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
                 val domainsIntent = Intent(this, DomainsActivity::class.java)
 
                 // Add the extra information to the intent.
-                domainsIntent.putExtra(CURRENT_URL, currentWebView!!.url)
                 domainsIntent.putExtra(CURRENT_IP_ADDRESSES, currentWebView!!.currentIpAddresses)
 
                 // Get the current certificate.
@@ -2440,7 +2611,7 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
                 // Add an open in new tab entry.
                 contextMenu.add(R.string.open_in_new_tab).setOnMenuItemClickListener {
                     // Load the link URL in a new tab and move to it.
-                    addNewTab(linkUrl, true)
+                    addNewPage(linkUrl, adjacent = true, moveToTab = true)
 
                     // Consume the event.
                     true
@@ -2449,7 +2620,7 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
                 // Add an open in background entry.
                 contextMenu.add(R.string.open_in_background).setOnMenuItemClickListener {
                     // Load the link URL in a new tab but do not move to it.
-                    addNewTab(linkUrl, false)
+                    addNewPage(linkUrl, adjacent = true, moveToTab = false)
 
                     // Consume the event.
                     true
@@ -2497,6 +2668,27 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
                     true
                 }
 
+                // Add a Share URL entry.
+                contextMenu.add(R.string.share_url).setOnMenuItemClickListener {
+                    // Create the share intent.
+                    val shareUrlIntent = Intent(Intent.ACTION_SEND)
+
+                    // Add the URL to the intent.
+                    shareUrlIntent.putExtra(Intent.EXTRA_TEXT, linkUrl)
+
+                    // Set the MIME type.
+                    shareUrlIntent.type = "text/plain"
+
+                    // Set the intent to open in a new task.
+                    shareUrlIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+
+                    //Make it so.
+                    startActivity(Intent.createChooser(shareUrlIntent, getString(R.string.share_url)))
+
+                    // Consume the event.
+                    true
+                }
+
                 // Add an empty cancel entry, which by default closes the context menu.
                 contextMenu.add(R.string.cancel)
             }
@@ -2515,7 +2707,7 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
                 // Add an open in new tab entry.
                 contextMenu.add(R.string.open_image_in_new_tab).setOnMenuItemClickListener {
                     // Load the image in a new tab.
-                    addNewTab(imageUrl, true)
+                    addNewPage(imageUrl, adjacent = true, moveToTab = true)
 
                     // Consume the event.
                     true
@@ -2573,6 +2765,27 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
                     true
                 }
 
+                // Add a Share URL entry.
+                contextMenu.add(R.string.share_url).setOnMenuItemClickListener {
+                    // Create the share intent.
+                    val shareUrlIntent = Intent(Intent.ACTION_SEND)
+
+                    // Add the URL to the intent.
+                    shareUrlIntent.putExtra(Intent.EXTRA_TEXT, imageUrl)
+
+                    // Set the MIME type.
+                    shareUrlIntent.type = "text/plain"
+
+                    // Set the intent to open in a new task.
+                    shareUrlIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+
+                    //Make it so.
+                    startActivity(Intent.createChooser(shareUrlIntent, getString(R.string.share_url)))
+
+                    // Consume the event.
+                    true
+                }
+
                 // Add an empty cancel entry, which by default closes the context menu.
                 contextMenu.add(R.string.cancel)
             }
@@ -2600,7 +2813,7 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
                 // Add an open in new tab entry.
                 contextMenu.add(R.string.open_in_new_tab).setOnMenuItemClickListener {
                     // Load the link URL in a new tab and move to it.
-                    addNewTab(linkUrl, true)
+                    addNewPage(linkUrl, adjacent = true, moveToTab = true)
 
                     // Consume the event.
                     true
@@ -2609,7 +2822,7 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
                 // Add an open in background entry.
                 contextMenu.add(R.string.open_in_background).setOnMenuItemClickListener {
                     // Lod the link URL in a new tab but do not move to it.
-                    addNewTab(linkUrl, false)
+                    addNewPage(linkUrl, adjacent = true, moveToTab = false)
 
                     // Consume the event.
                     true
@@ -2618,7 +2831,7 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
                 // Add an open image in new tab entry.
                 contextMenu.add(R.string.open_image_in_new_tab).setOnMenuItemClickListener {
                     // Load the image in a new tab and move to it.
-                    addNewTab(imageUrl, true)
+                    addNewPage(imageUrl, adjacent = true, moveToTab = true)
 
                     // Consume the event.
                     true
@@ -2663,6 +2876,27 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
                     true
                 }
 
+                // Add a Share Image entry.
+                contextMenu.add(R.string.share_image).setOnMenuItemClickListener {
+                    // Create the share intent.
+                    val shareUrlIntent = Intent(Intent.ACTION_SEND)
+
+                    // Add the URL to the intent.
+                    shareUrlIntent.putExtra(Intent.EXTRA_TEXT, imageUrl)
+
+                    // Set the MIME type.
+                    shareUrlIntent.type = "text/plain"
+
+                    // Set the intent to open in a new task.
+                    shareUrlIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+
+                    //Make it so.
+                    startActivity(Intent.createChooser(shareUrlIntent, getString(R.string.share_url)))
+
+                    // Consume the event.
+                    true
+                }
+
                 // Add a copy URL entry.
                 contextMenu.add(R.string.copy_url).setOnMenuItemClickListener {
                     // Save the link URL in a clip data.
@@ -2687,6 +2921,27 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
                     true
                 }
 
+                // Add a Share URL entry.
+                contextMenu.add(R.string.share_url).setOnMenuItemClickListener {
+                    // Create the share intent.
+                    val shareUrlIntent = Intent(Intent.ACTION_SEND)
+
+                    // Add the URL to the intent.
+                    shareUrlIntent.putExtra(Intent.EXTRA_TEXT, linkUrl)
+
+                    // Set the MIME type.
+                    shareUrlIntent.type = "text/plain"
+
+                    // Set the intent to open in a new task.
+                    shareUrlIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+
+                    //Make it so.
+                    startActivity(Intent.createChooser(shareUrlIntent, getString(R.string.share_url)))
+
+                    // Consume the event.
+                    true
+                }
+
                 // Add an empty cancel entry, which by default closes the context menu.
                 contextMenu.add(R.string.cancel)
             }
@@ -2742,35 +2997,72 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
     // The view parameter cannot be removed because it is called from the layout onClick.
     fun addTab(@Suppress("UNUSED_PARAMETER")view: View?) {
         // Add a new tab with a blank URL.
-        addNewTab("", true)
+        addNewPage(urlString = "", adjacent = true, moveToTab = true)
     }
 
-    private fun addNewTab(urlString: String, moveToTab: Boolean) {
+    private fun addNewPage(urlString: String, adjacent: Boolean, moveToTab: Boolean) {
         // Clear the focus from the URL edit text, so that it will be populated with the information from the new tab.
         urlEditText.clearFocus()
 
-        // Get the new page number.  The page numbers are 0 indexed, so the new page number will match the current count.
-        val newTabNumber = tabLayout.tabCount
+        // Add the new tab after the tab layout has quiesced.
+        // Otherwise, there can be problems when restoring a large number of tabs and processing a new intent at the same time.  <https://redmine.stoutner.com/issues/1136>
+        tabLayout.post {
+            // Get the new tab position.
+            val newTabPosition = if (adjacent)  // The new tab position is immediately to the right of the current tab position.
+                tabLayout.selectedTabPosition + 1
+            else  // The new tab position is at the end.  The tab positions are 0 indexed, so the new page number will match the current count.
+                tabLayout.tabCount
 
-        // Add a new tab.
-        tabLayout.addTab(tabLayout.newTab())
+            // Add the new WebView page.
+            webViewStateAdapter!!.addPage(newTabPosition, urlString)
 
-        // Get the new tab.
-        val newTab = tabLayout.getTabAt(newTabNumber)!!
+            // Add the new tab.
+            addNewTab(newTabPosition, moveToTab)
+        }
+    }
 
-        // Set a custom view on the new tab.
-        newTab.setCustomView(R.layout.tab_custom_view)
+    private fun addNewTab(newTabPosition: Int, moveToTab: Boolean) {
+        // Check to see if the new page is ready.
+        if (webViewStateAdapter!!.itemCount >= tabLayout.tabCount) {  // The new page is ready.
+            // Create a new tab.
+            val newTab = tabLayout.newTab()
 
-        // Add the new WebView page.
-        webViewStateAdapter!!.addPage(newTabNumber, webViewViewPager2, urlString, moveToTab)
+            // Set a custom view on the new tab.
+            newTab.setCustomView(R.layout.tab_custom_view)
 
-        // Show the app bar if it is at the bottom of the screen and the new tab is taking focus.
-        if (bottomAppBar && moveToTab && appBarLayout.translationY != 0f) {
-            // Animate the bottom app bar onto the screen.
-            objectAnimator = ObjectAnimator.ofFloat(appBarLayout, "translationY", 0f)
+            // Add the new tab.
+            tabLayout.addTab(newTab, newTabPosition, moveToTab)
 
-            // Make it so.
-            objectAnimator.start()
+            // Select the new tab if it is the first one.  For some odd reason, Android doesn't select the first tab if it is the only one, which causes problems with the new tab position logic above.
+            if (newTabPosition == 0)
+                tabLayout.selectTab(newTab)
+
+            // Scroll to the new tab position if moving to the new tab.
+            if (moveToTab)
+                tabLayout.post {
+                    tabLayout.setScrollPosition(newTabPosition, 0F, false, false)
+                }
+
+            // Show the app bar if it is at the bottom of the screen and the new tab is taking focus.
+            if (bottomAppBar && moveToTab && appBarLayout.translationY != 0f) {
+                // Animate the bottom app bar onto the screen.
+                objectAnimator = ObjectAnimator.ofFloat(appBarLayout, "translationY", 0f)
+
+                // Make it so.
+                objectAnimator.start()
+            }
+        } else {  // The new page is not ready.
+            // Create a new tab handler.
+            val newTabHandler = Handler(Looper.getMainLooper())
+
+            // Create a new tab runnable.
+            val newTabRunnable = Runnable {
+                // Create the new tab.
+                addNewTab(newTabPosition, moveToTab)
+            }
+
+            // Try adding the new tab again after 50 milliseconds.
+            newTabHandler.postDelayed(newTabRunnable, 50)
         }
     }
 
@@ -2797,9 +3089,13 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
         // Get the WebView theme entry values string array.  This is done here so that expensive resource requests are not made each time a domain is loaded.
         webViewThemeEntryValuesStringArray = resources.getStringArray(R.array.webview_theme_entry_values)
 
-        // Get the user agent array adapter and string array.  These are done here so that expensive resource requests are not made each time a domain is loaded.
-        userAgentNamesArray = ArrayAdapter.createFromResource(this, R.array.user_agent_names, R.layout.spinner_item)
+        // Get the user agent string arrays.  These are done here so that expensive resource requests are not made each time a domain is loaded.
         userAgentDataArray = resources.getStringArray(R.array.user_agent_data)
+        userAgentNamesArray = resources.getStringArray(R.array.user_agent_names)
+
+        // Get the user agent array adapters.  These are done here so that expensive resource requests are not made each time a domain is loaded.
+        userAgentDataArrayAdapter = ArrayAdapter.createFromResource(this, R.array.user_agent_data, R.layout.spinner_item)
+        userAgentNamesArrayAdapter = ArrayAdapter.createFromResource(this, R.array.user_agent_names, R.layout.spinner_item)
 
         // Store the values from the shared preferences in variables.
         incognitoModeEnabled = sharedPreferences.getBoolean(getString(R.string.incognito_mode_key), false)
@@ -2809,7 +3105,7 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
         fullScreenBrowsingModeEnabled = sharedPreferences.getBoolean(getString(R.string.full_screen_browsing_mode_key), false)
         hideAppBar = sharedPreferences.getBoolean(getString(R.string.hide_app_bar_key), true)
         downloadWithExternalApp = sharedPreferences.getBoolean(getString(R.string.download_with_external_app_key), false)
-        scrollAppBar = sharedPreferences.getBoolean(getString(R.string.scroll_app_bar_key), true)
+        scrollAppBar = sharedPreferences.getBoolean(getString(R.string.scroll_app_bar_key), false)
 
         // Apply the saved proxy mode if the app has been restarted.
         if (savedProxyMode != null) {
@@ -2986,6 +3282,10 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
                     val tabFavoriteIconImageView = tabCustomView.findViewById<ImageView>(R.id.favorite_icon_imageview)
                     val tabTitleTextView = tabCustomView.findViewById<TextView>(R.id.title_textview)
 
+                    // Store the current values in case they need to be restored.
+                    nestedScrollWebView.previousFavoriteIconDrawable = tabFavoriteIconImageView.drawable
+                    nestedScrollWebView.previousWebpageTitle = tabTitleTextView.text.toString()
+
                     // Set the default favorite icon as the favorite icon for this tab.
                     tabFavoriteIconImageView.setImageBitmap(Bitmap.createScaledBitmap(nestedScrollWebView.getFavoriteIcon(), 64, 64, true))
 
@@ -3152,23 +3452,22 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
                 // Set the user agent.
                 if (userAgentName == getString(R.string.system_default_user_agent)) {  // Use the system default user agent.
                     // Set the user agent according to the system default.
-                    when (val defaultUserAgentArrayPosition = userAgentNamesArray.getPosition(defaultUserAgentName)) {
-                        // This is probably because it was set in an older version of Privacy Browser before the switch to persistent user agent names.
-                        UNRECOGNIZED_USER_AGENT -> nestedScrollWebView.settings.userAgentString = defaultUserAgentName
+                    when (val defaultUserAgentArrayPosition = userAgentNamesArrayAdapter.getPosition(defaultUserAgentName)) {
+                        UNRECOGNIZED_USER_AGENT ->  // This is probably because it was set in an older version of Privacy Browser before the switch to persistent user agent names.
+                            nestedScrollWebView.settings.userAgentString = defaultUserAgentName
 
-                        // Set the user agent to `""`, which uses the default value.
-                        SETTINGS_WEBVIEW_DEFAULT_USER_AGENT -> nestedScrollWebView.settings.userAgentString = ""
+                        SETTINGS_WEBVIEW_DEFAULT_USER_AGENT ->  // Set the user agent to `""`, which uses the default value.
+                            nestedScrollWebView.settings.userAgentString = ""
 
-                        // Set the default custom user agent.
-                        SETTINGS_CUSTOM_USER_AGENT -> nestedScrollWebView.settings.userAgentString =
-                            sharedPreferences.getString(getString(R.string.custom_user_agent_key), getString(R.string.custom_user_agent_default_value))
+                        SETTINGS_CUSTOM_USER_AGENT ->  // Set the default custom user agent.
+                            nestedScrollWebView.settings.userAgentString = sharedPreferences.getString(getString(R.string.custom_user_agent_key), getString(R.string.custom_user_agent_default_value))
 
-                        // Get the user agent string from the user agent data array
-                        else -> nestedScrollWebView.settings.userAgentString = userAgentDataArray[defaultUserAgentArrayPosition]
+                        else ->  // Get the user agent string from the user agent data array
+                            nestedScrollWebView.settings.userAgentString = userAgentDataArray[defaultUserAgentArrayPosition]
                     }
                 } else {  // Set the user agent according to the stored name.
                     // Set the user agent.
-                    when (val userAgentArrayPosition = userAgentNamesArray.getPosition(userAgentName)) {
+                    when (val userAgentArrayPosition = userAgentNamesArrayAdapter.getPosition(userAgentName)) {
                         // This is probably because it was set in an older version of Privacy Browser before the switch to persistent user agent names.
                         UNRECOGNIZED_USER_AGENT ->
                             nestedScrollWebView.settings.userAgentString = userAgentName
@@ -3239,17 +3538,15 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
                 if (WebViewFeature.isFeatureSupported(WebViewFeature.ALGORITHMIC_DARKENING)) {
                     // Set the WebView theme.
                     when (webViewThemeInt) {
-                        // Set the WebView theme.
-                        SYSTEM_DEFAULT ->
+                        SYSTEM_DEFAULT ->  // Set the WebView theme.
                             when (defaultWebViewTheme) {
-                                // The light theme is selected.  Turn off algorithmic darkening.
-                                webViewThemeEntryValuesStringArray[1] -> WebSettingsCompat.setAlgorithmicDarkeningAllowed(nestedScrollWebView.settings, false)
+                                webViewThemeEntryValuesStringArray[1] ->  // The light theme is selected.  Turn off algorithmic darkening.
+                                    WebSettingsCompat.setAlgorithmicDarkeningAllowed(nestedScrollWebView.settings, false)
 
-                                // The dark theme is selected.  Turn on algorithmic darkening.
-                                webViewThemeEntryValuesStringArray[2] -> WebSettingsCompat.setAlgorithmicDarkeningAllowed(nestedScrollWebView.settings, true)
+                                webViewThemeEntryValuesStringArray[2] ->  // The dark theme is selected.  Turn on algorithmic darkening.
+                                    WebSettingsCompat.setAlgorithmicDarkeningAllowed(nestedScrollWebView.settings, true)
 
-                                // The system default theme is selected.
-                                else -> {
+                                else -> {  // The system default theme is selected.
                                     // Get the current system theme status.
                                     val currentThemeStatus = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
 
@@ -3258,11 +3555,11 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
                                 }
                             }
 
-                        // Turn off algorithmic darkening.
-                        LIGHT_THEME -> WebSettingsCompat.setAlgorithmicDarkeningAllowed(nestedScrollWebView.settings, false)
+                        LIGHT_THEME ->  // Turn off algorithmic darkening.
+                            WebSettingsCompat.setAlgorithmicDarkeningAllowed(nestedScrollWebView.settings, false)
 
-                        // Turn on algorithmic darkening.
-                        DARK_THEME -> WebSettingsCompat.setAlgorithmicDarkeningAllowed(nestedScrollWebView.settings, true)
+                        DARK_THEME ->  // Turn on algorithmic darkening.
+                            WebSettingsCompat.setAlgorithmicDarkeningAllowed(nestedScrollWebView.settings, true)
                     }
                 }
 
@@ -3340,33 +3637,31 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
                 nestedScrollWebView.domainSettingsDatabaseId = -1
 
                 // Set the user agent.
-                when (val userAgentArrayPosition = userAgentNamesArray.getPosition(defaultUserAgentName)) {
-                    // This is probably because it was set in an older version of Privacy Browser before the switch to persistent user agent names.
-                    UNRECOGNIZED_USER_AGENT -> nestedScrollWebView.settings.userAgentString = defaultUserAgentName
+                when (val userAgentArrayPosition = userAgentNamesArrayAdapter.getPosition(defaultUserAgentName)) {
+                    UNRECOGNIZED_USER_AGENT ->  // This is probably because it was set in an older version of Privacy Browser before the switch to persistent user agent names.
+                        nestedScrollWebView.settings.userAgentString = defaultUserAgentName
 
-                    // Set the user agent to `""`, which uses the default value.
-                    SETTINGS_WEBVIEW_DEFAULT_USER_AGENT -> nestedScrollWebView.settings.userAgentString = ""
+                    SETTINGS_WEBVIEW_DEFAULT_USER_AGENT ->  // Set the user agent to `""`, which uses the default value.
+                        nestedScrollWebView.settings.userAgentString = ""
 
-                    // Set the default custom user agent.
-                    SETTINGS_CUSTOM_USER_AGENT -> nestedScrollWebView.settings.userAgentString =
-                        sharedPreferences.getString(getString(R.string.custom_user_agent_key), getString(R.string.custom_user_agent_default_value))
+                    SETTINGS_CUSTOM_USER_AGENT ->  // Set the default custom user agent.
+                        nestedScrollWebView.settings.userAgentString = sharedPreferences.getString(getString(R.string.custom_user_agent_key), getString(R.string.custom_user_agent_default_value))
 
-                    // Get the user agent string from the user agent data array
-                    else -> nestedScrollWebView.settings.userAgentString = userAgentDataArray[userAgentArrayPosition]
+                    else ->  // Get the user agent string from the user agent data array
+                        nestedScrollWebView.settings.userAgentString = userAgentDataArray[userAgentArrayPosition]
                 }
 
                 // Set the WebView theme if algorithmic darkening is supported.
                 if (WebViewFeature.isFeatureSupported(WebViewFeature.ALGORITHMIC_DARKENING)) {
                     // Set the WebView theme.
                     when (defaultWebViewTheme) {
-                        // The light theme is selected.  Turn off algorithmic darkening.
-                        webViewThemeEntryValuesStringArray[1] -> WebSettingsCompat.setAlgorithmicDarkeningAllowed(nestedScrollWebView.settings, false)
+                        webViewThemeEntryValuesStringArray[1] ->  // The light theme is selected.  Turn off algorithmic darkening.
+                            WebSettingsCompat.setAlgorithmicDarkeningAllowed(nestedScrollWebView.settings, false)
 
-                        // The dark theme is selected.  Turn on algorithmic darkening.
-                        webViewThemeEntryValuesStringArray[2] -> WebSettingsCompat.setAlgorithmicDarkeningAllowed(nestedScrollWebView.settings, true)
+                        webViewThemeEntryValuesStringArray[2] ->  // The dark theme is selected.  Turn on algorithmic darkening.
+                            WebSettingsCompat.setAlgorithmicDarkeningAllowed(nestedScrollWebView.settings, true)
 
-                        // The system default theme is selected.  Get the current system theme status.
-                        else -> {
+                        else -> {  // The system default theme is selected.  Get the current system theme status.
                             // Get the current theme status.
                             val currentThemeStatus = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
 
@@ -3394,6 +3689,10 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
         if (reloadWebsite)
             nestedScrollWebView.reload()
 
+        // Disable the wide viewport if the source is being viewed.
+        if (url.startsWith("view-source:"))
+            nestedScrollWebView.settings.useWideViewPort = false
+
         // Load the URL if directed.  This makes sure that the domain settings are properly loaded before the URL.  By using `loadUrl()`, instead of `loadUrlFromBase()`, the Referer header will never be sent.
         if (loadUrl)
             nestedScrollWebView.loadUrl(url)
@@ -3431,8 +3730,7 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
                     // Get the package manager.
                     val packageManager = packageManager
 
-                    // Check to see if Orbot is in the list.  This will throw an error and drop to the catch section if it isn't installed.  The deprecated method must be used until the minimum API >= 33.
-                    @Suppress("DEPRECATION")
+                    // Check to see if Orbot is in the list.  This will throw an error and drop to the catch section if it isn't installed.
                     packageManager.getPackageInfo("org.torproject.android", 0)
 
                     // Check to see if the proxy is ready.
@@ -3480,14 +3778,10 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
                 // Check to see if I2P is installed.
                 try {
                     // Check to see if the F-Droid flavor is installed.  This will throw an error and drop to the catch section if it isn't installed.
-                    // The deprecated method must be used until the minimum API >= 33.
-                    @Suppress("DEPRECATION")
                     packageManager.getPackageInfo("net.i2p.android.router", 0)
                 } catch (fdroidException: PackageManager.NameNotFoundException) {  // The F-Droid flavor is not installed.
                     try {
                         // Check to see if the Google Play flavor is installed.  This will throw an error and drop to the catch section if it isn't installed.
-                        // The deprecated method must be used until the minimum API >= 33.
-                        @Suppress("DEPRECATION")
                         packageManager.getPackageInfo("net.i2p.android", 0)
                     } catch (googlePlayException: PackageManager.NameNotFoundException) {  // The Google Play flavor is not installed.
                         // Sow the I2P not installed dialog if it is not already displayed.
@@ -3549,6 +3843,15 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
         }
     }
 
+    private fun calculateSettingsInt(settingCurrentlyEnabled: Boolean, settingEnabledByDefault: Boolean): Int {
+        return if (settingCurrentlyEnabled == settingEnabledByDefault)  // The current system default is used.
+            SYSTEM_DEFAULT
+        else if (settingCurrentlyEnabled)  // The setting is enabled, which is different from the system default.
+            ENABLED
+        else  // The setting is disabled, which is different from the system default.
+            DISABLED
+    }
+
     private fun clearAndExit() {
         // Close the bookmarks cursor if it exists.
         bookmarksCursor?.close()
@@ -3855,11 +4158,11 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
             val databaseId = bookmarksListView.getItemIdAtPosition(i).toInt()
 
             // Move the bookmark down one slot.
-            bookmarksDatabaseHelper!!.updateDisplayOrder(databaseId, i + 1)
+            bookmarksDatabaseHelper!!.updateDisplayOrder(databaseId, displayOrder = i + 1)
         }
 
         // Create the folder, which will be placed at the top of the list view.
-        bookmarksDatabaseHelper!!.createFolder(folderNameString, currentBookmarksFolderId, folderIconByteArray)
+        bookmarksDatabaseHelper!!.createFolder(folderNameString, currentBookmarksFolderId, displayOrder = 0, folderIconByteArray)
 
         // Update the bookmarks cursor with the current contents of this folder.
         bookmarksCursor = bookmarksDatabaseHelper!!.getBookmarksByDisplayOrder(currentBookmarksFolderId)
@@ -3956,8 +4259,8 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
         // Check to see if the activity has been restarted with a saved state.
         if ((savedStateArrayList == null) || (savedStateArrayList!!.size == 0)) {  // The activity has not been restarted or it was restarted on start to change the theme.
             // Add the first tab.
-            addNewTab("", false)
-        } else {  // The activity has been restarted.
+            addNewPage(urlString = "", adjacent = false, moveToTab = false)
+        } else {  // The activity has been restarted with a saved state.
             // Restore each tab.
             for (i in savedStateArrayList!!.indices) {
                 // Add a new tab.
@@ -3977,24 +4280,6 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
             savedStateArrayList = null
             savedNestedScrollWebViewStateArrayList = null
 
-            // Restore the selected tab position.
-            if (savedTabPosition == 0) {  // The first tab is selected.
-                // Set the first page as the current WebView.
-                setCurrentWebView(0)
-            } else {  // The first tab is not selected.
-                // Create a handler move to the page.
-                val setCurrentPageHandler = Handler(Looper.getMainLooper())
-
-                // Create a runnable to move to the page.
-                val setCurrentPageRunnable = Runnable {
-                    // Move to the page.
-                    webViewViewPager2.currentItem = savedTabPosition
-                }
-
-                // Move to the page after 50 milliseconds, which should be enough time to for the WebView state adapter to populate the restored pages.
-                setCurrentPageHandler.postDelayed(setCurrentPageRunnable, 50)
-            }
-
             // Get the intent that started the app.
             val intent = intent
 
@@ -4010,7 +4295,7 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
             val isWebSearch = (intentAction != null) && (intentAction == Intent.ACTION_WEB_SEARCH)
 
             // 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) {
+            if ((intentUriData != null) || (intentStringExtra != null) || isWebSearch) {  // A new tab is being loaded.
                 // Get the URL string.
                 val urlString = if (isWebSearch) {  // The intent is a web search.
                     // Sanitize the search input.
@@ -4033,11 +4318,26 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
                     loadingNewIntent = true
 
                     // Add a new tab.
-                    addNewTab(urlString, true)
+                    addNewPage(urlString, adjacent = false, moveToTab = true)
                 } else {  // Load the URL in the current tab.
                     // Make it so.
                     loadUrl(currentWebView!!, urlString)
                 }
+            } else {  // A new tab is not being loaded.
+                // Restore the selected tab position.
+                if (savedTabPosition == 0) {  // The first tab is selected.
+                    // Set the first page as the current WebView.
+                    setCurrentWebView(0)
+                } else {  // The first tab is not selected.
+                    // Select the tab when the layout has finished populating.
+                    tabLayout.post {
+                        // Get a handle for the tab.
+                        val tab = tabLayout.getTabAt(savedTabPosition)!!
+
+                        // Select the tab.
+                        tab.select()
+                    }
+                }
             }
         }
     }
@@ -4143,8 +4443,8 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
             }
         }
 
-        // Register the Orbot status broadcast receiver.
-        registerReceiver(orbotStatusBroadcastReceiver, IntentFilter("org.torproject.android.intent.action.STATUS"))
+        // Register the Orbot status broadcast receiver.  `ContextCompat` must be used until the minimum API >= 34.
+        ContextCompat.registerReceiver(this, orbotStatusBroadcastReceiver, IntentFilter("org.torproject.android.intent.action.STATUS"), ContextCompat.RECEIVER_EXPORTED)
 
         // Get handles for views that need to be modified.
         val bookmarksHeaderLinearLayout = findViewById<LinearLayout>(R.id.bookmarks_header_linearlayout)
@@ -4152,44 +4452,36 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
         val createBookmarkFolderFab = findViewById<FloatingActionButton>(R.id.create_bookmark_folder_fab)
         val createBookmarkFab = findViewById<FloatingActionButton>(R.id.create_bookmark_fab)
 
-        // Update the WebView pager every time a tab is modified.
-        webViewViewPager2.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
-            override fun onPageSelected(position: Int) {
+        // Handle tab selections.
+        tabLayout.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
+            override fun onTabSelected(tab: TabLayout.Tab) {
                 // Close the find on page bar if it is open.
                 closeFindOnPage(null)
 
-                // Set the current WebView.
-                setCurrentWebView(position)
+                // Update the view pager when it has quiesced.  Otherwise, if a page launched by a new intent on restart has not yet been created, the view pager will not be updated to match the tab layout.
+                webViewViewPager2.post {
+                    // Select the same page in the view pager.
+                    webViewViewPager2.currentItem = tab.position
 
-                // Select the corresponding tab if it does not match the currently selected page.  This will happen if the page was scrolled by creating a new tab.
-                if (tabLayout.selectedTabPosition != position) {
-                    // Wait until the new tab has been created.
+                    // Set the current WebView after the tab layout has quiesced (otherwise, sometimes the wong WebView might be used).  See <https://redmine.stoutner.com/issues/1136>
                     tabLayout.post {
-                        // Get a handle for the tab.
-                        val tab = tabLayout.getTabAt(position)!!
-
-                        // Select the tab.
-                        tab.select()
+                        setCurrentWebView(tab.position)
                     }
                 }
             }
-        })
-
-        // Handle tab selections.
-        tabLayout.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
-            override fun onTabSelected(tab: TabLayout.Tab) {
-                // Select the same page in the view pager.
-                webViewViewPager2.currentItem = tab.position
-            }
 
             override fun onTabUnselected(tab: TabLayout.Tab) {}
 
             override fun onTabReselected(tab: TabLayout.Tab) {
-                // Instantiate the View SSL Certificate dialog.
-                val viewSslCertificateDialogFragment: DialogFragment = ViewSslCertificateDialog.displayDialog(currentWebView!!.webViewFragmentId, currentWebView!!.getFavoriteIcon())
-
-                // Display the View SSL Certificate dialog.
-                viewSslCertificateDialogFragment.show(supportFragmentManager, getString(R.string.view_ssl_certificate))
+                // Only display the view SSL certificate dialog if the current WebView is not null.
+                // This can happen if the tab is programmatically reselected while the app is being restarted and is not yet populated.
+                if (currentWebView != null) {
+                    // Instantiate the View SSL Certificate dialog.
+                    val viewSslCertificateDialogFragment: DialogFragment = ViewSslCertificateDialog.displayDialog(currentWebView!!.webViewFragmentId, currentWebView!!.getFavoriteIcon())
+
+                    // Display the View SSL Certificate dialog.
+                    viewSslCertificateDialogFragment.show(supportFragmentManager, getString(R.string.view_ssl_certificate))
+                }
             }
         })
 
@@ -4349,7 +4641,7 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
                 // Open each bookmark
                 for (i in 0 until bookmarksCursor.count) {
                     // Load the bookmark in a new tab, moving to the tab for the first bookmark if the drawer is not pinned.
-                    addNewTab(bookmarksCursor.getString(bookmarksCursor.getColumnIndexOrThrow(BOOKMARK_URL)), !bookmarksDrawerPinned && (i == 0))
+                    addNewPage(bookmarksCursor.getString(bookmarksCursor.getColumnIndexOrThrow(BOOKMARK_URL)), adjacent = false, moveToTab = !bookmarksDrawerPinned && (i == 0))
 
                     // Move to the next bookmark.
                     bookmarksCursor.moveToNext()
@@ -4365,7 +4657,7 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
                 bookmarkCursor.moveToFirst()
 
                 // Load the bookmark in a new tab and move to the tab if the drawer is not pinned.
-                addNewTab(bookmarkCursor.getString(bookmarkCursor.getColumnIndexOrThrow(BOOKMARK_URL)), !bookmarksDrawerPinned)
+                addNewPage(bookmarkCursor.getString(bookmarkCursor.getColumnIndexOrThrow(BOOKMARK_URL)), adjacent = true, moveToTab = !bookmarksDrawerPinned)
 
                 // Close the cursor.
                 bookmarkCursor.close()
@@ -4385,18 +4677,34 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
 
             override fun onDrawerOpened(drawerView: View) {}
 
-            override fun onDrawerClosed(drawerView: View) {
-                // Reset the drawer icon when the drawer is closed.  Otherwise, it remains an arrow if the drawer is open when the app is restarted.
-                actionBarDrawerToggle!!.syncState()
-            }
+            override fun onDrawerClosed(drawerView: View) {}
 
             override fun onDrawerStateChanged(newState: Int) {
                 if (newState == DrawerLayout.STATE_SETTLING || newState == DrawerLayout.STATE_DRAGGING) {  // A drawer is opening or closing.
                     // Update the navigation menu items if the WebView is not null.
                     if (currentWebView != null) {
+                        // Set the enabled status of the menu items.
                         navigationBackMenuItem.isEnabled = currentWebView!!.canGoBack()
                         navigationForwardMenuItem.isEnabled = currentWebView!!.canGoForward()
+                        navigationScrollToBottomMenuItem.isEnabled = (currentWebView!!.canScrollVertically(-1) || currentWebView!!.canScrollVertically(1))
                         navigationHistoryMenuItem.isEnabled = currentWebView!!.canGoBack() || currentWebView!!.canGoForward()
+
+                        // Update the scroll menu item.
+                        if (currentWebView!!.scrollY == 0) {  // The WebView is scrolled to the top.
+                            // Set the title.
+                            navigationScrollToBottomMenuItem.title = getString(R.string.scroll_to_bottom)
+
+                            // Set the icon.
+                            navigationScrollToBottomMenuItem.icon = AppCompatResources.getDrawable(applicationContext, R.drawable.move_down_enabled)
+                        } else {  // The WebView is not scrolled to the top.
+                            // Set the title.
+                            navigationScrollToBottomMenuItem.title = getString(R.string.scroll_to_top)
+
+                            // Set the icon.
+                            navigationScrollToBottomMenuItem.icon = AppCompatResources.getDrawable(applicationContext, R.drawable.move_up_enabled)
+                        }
+
+                        // Display the number of blocked requests.
                         navigationRequestsMenuItem.title = getString(R.string.requests) + " - " + currentWebView!!.getRequestsCount(BLOCKED_REQUESTS)
 
                         // Hide the keyboard (if displayed).
@@ -4409,6 +4717,20 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
                     // Clear the focus from from the WebView if it is not null, which can happen if a user opens a drawer while the browser is being resumed.
                     // Clearing the focus from the WebView removes any text selection markers and context menus, which otherwise draw above the open drawers.
                     currentWebView?.clearFocus()
+
+                    if (bottomAppBar && navigationDrawerFirstView) {
+                        // Reset the navigation drawer first view flag.
+                        navigationDrawerFirstView = false
+
+                        // Get a handle for the navigation recycler view.
+                        val navigationRecyclerView = navigationView.getChildAt(0) as RecyclerView
+
+                        // Get the navigation linear layout manager.
+                        val navigationLinearLayoutManager = navigationRecyclerView.layoutManager as LinearLayoutManager
+
+                        // Scroll the navigation drawer to the bottom.
+                        navigationLinearLayoutManager.scrollToPositionWithOffset(13, 0)
+                    }
                 }
             }
         })
@@ -4433,7 +4755,7 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
     }
 
     @SuppressLint("ClickableViewAccessibility")
-    override fun initializeWebView(nestedScrollWebView: NestedScrollWebView, pageNumber: Int, progressBar: ProgressBar, urlString: String, restoringState: Boolean) {
+    override fun initializeWebView(nestedScrollWebView: NestedScrollWebView, pagePosition: Int, progressBar: ProgressBar, urlString: String, restoringState: Boolean) {
         // Get the WebView theme.
         val webViewTheme = sharedPreferences.getString(getString(R.string.webview_theme_key), getString(R.string.webview_theme_default_value))
 
@@ -4560,8 +4882,7 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
 
                         // The deprecated command can be switched to `WindowInsetsController` once the minimum API >= 30.
                         @Suppress("DEPRECATION")
-                        rootFrameLayout.systemUiVisibility = View.SYSTEM_UI_FLAG_FULLSCREEN or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or
-                                View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
+                        rootFrameLayout.systemUiVisibility = View.SYSTEM_UI_FLAG_FULLSCREEN or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
                     } else {  // Switch to normal viewing mode.
                         // Show the app bar if it was hidden.
                         if (hideAppBar) {
@@ -4612,9 +4933,9 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
                 }
             }
 
-            override fun onFling(motionEvent1: MotionEvent, motionEvent2: MotionEvent, velocityX: Float, velocityY: Float): Boolean {
+            override fun onFling(motionEvent1: MotionEvent?, motionEvent2: MotionEvent, velocityX: Float, velocityY: Float): Boolean {
                 // Scroll the bottom app bar if enabled.
-                if (bottomAppBar && scrollAppBar && !objectAnimator.isRunning) {
+                if (bottomAppBar && scrollAppBar && !objectAnimator.isRunning && (motionEvent1 != null)) {
                     // Calculate the Y change.
                     val motionY = motionEvent2.y - motionEvent1.y
 
@@ -4680,6 +5001,29 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
                     pendingDialogsArrayList.add(PendingDialogDataClass(saveDialogFragment, getString(R.string.save_dialog)))
                 }
             }
+
+            // Get the current page position.
+            val currentPagePosition = webViewStateAdapter!!.getPositionForId(nestedScrollWebView.webViewFragmentId)
+
+            // Get the corresponding tab.
+            val tab = tabLayout.getTabAt(currentPagePosition)!!
+
+            // Get the tab custom view.
+            val tabCustomView = tab.customView!!
+
+            // Get the tab views.
+            val tabFavoriteIconImageView = tabCustomView.findViewById<ImageView>(R.id.favorite_icon_imageview)
+            val tabTitleTextView = tabCustomView.findViewById<TextView>(R.id.title_textview)
+
+            // Restore the previous webpage favorite icon and title if the title is currently set to `Loading...`.
+            if (tabTitleTextView.text.toString() == getString(R.string.loading)) {
+                // Restore the previous webpage title text.
+                tabTitleTextView.text = nestedScrollWebView.previousWebpageTitle
+
+                // Restore the previous webpage favorite icon if it is not null.
+                if (nestedScrollWebView.previousFavoriteIconDrawable != null)
+                    tabFavoriteIconImageView.setImageDrawable(nestedScrollWebView.previousFavoriteIconDrawable)
+            }
         }
 
         // Update the find on page count.
@@ -5351,8 +5695,8 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
 
                 // Update the URL text bar if the page is currently selected and the URL edit text is not currently being edited.
                 if ((tabLayout.selectedTabPosition == currentPagePosition) && !urlEditText.hasFocus()) {
-                    // Display the formatted URL text.
-                    urlEditText.setText(url)
+                    // Display the formatted URL text.  The nested scroll WebView current URL preserves any initial `view-source:`, and opposed to the method URL variable.
+                    urlEditText.setText(nestedScrollWebView.currentUrl)
 
                     // Highlight the URL syntax.
                     UrlHelper.highlightSyntax(urlEditText, initialGrayColorSpan, finalGrayColorSpan, redColorSpan)
@@ -5558,7 +5902,7 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
         if (restoringState) {  // The state is being restored.
             // Resume the nested scroll WebView JavaScript timers.
             nestedScrollWebView.resumeTimers()
-        } else if (pageNumber == 0) {  // The first page is being loaded.
+        } else if (pagePosition == 0) {  // The first page is being loaded.
             // Set this nested scroll WebView as the current WebView.
             currentWebView = nestedScrollWebView
 
@@ -5604,10 +5948,6 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
             } else {  // Load the URL.
                 loadUrl(nestedScrollWebView, urlToLoadString!!)
             }
-
-            // Reset the intent.  This prevents a duplicate tab from being created on a subsequent restart if loading an link from a new intent on restart.
-            // For example, this prevents a duplicate tab if a link is loaded from the Guide after changing the theme in the guide and then changing the theme again in the main activity.
-            intent = Intent()
         } else {  // This is not the first tab.
             // Load the URL.
             loadUrl(nestedScrollWebView, urlString)
@@ -5617,17 +5957,10 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
                 // Request focus for the URL text box.
                 urlEditText.requestFocus()
 
-                // Create a display keyboard handler.
-                val displayKeyboardHandler = Handler(Looper.getMainLooper())
-
-                // Create a display keyboard runnable.
-                val displayKeyboardRunnable = Runnable {
-                    // Display the keyboard.
+                // Display the keyboard once the tab layout has settled.
+                tabLayout.post {
                     inputMethodManager.showSoftInput(urlEditText, 0)
                 }
-
-                // Display the keyboard after 100 milliseconds, which leaves enough time for the tab to transition.
-                displayKeyboardHandler.postDelayed(displayKeyboardRunnable, 100)
             }
         }
     }
@@ -5694,7 +6027,7 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
         var urlString = ""
 
         // Check to see if the unformatted URL string is a valid URL.  Otherwise, convert it into a search.
-        if (unformattedUrlString.startsWith("content://")) {  // This is a content URL.
+        if (unformattedUrlString.startsWith("content://") || unformattedUrlString.startsWith("view-source:")) {  // This is a content or source URL.
             // Load the entire content URL.
             urlString = unformattedUrlString
         } else if (Patterns.WEB_URL.matcher(unformattedUrlString).matches() || unformattedUrlString.startsWith("http://") || unformattedUrlString.startsWith("https://") ||
@@ -5758,6 +6091,9 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
 
         // Load the history entry.
         currentWebView!!.goBackOrForward(steps)
+
+        // Update the URL edit text after a delay.
+        updateUrlEditTextAfterDelay()
     }
 
     override fun openFile(dialogFragment: DialogFragment) {
@@ -5814,6 +6150,11 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
             currentWebView!!.loadUrl(openFilePath)
         }
     }
+    // The view parameter cannot be removed because it is called from the layout onClick.
+    fun openNavigationDrawer(@Suppress("UNUSED_PARAMETER")view: View) {
+        // Open the navigation drawer.
+        drawerLayout.openDrawer(GravityCompat.START)
+    }
 
     private fun openWithApp(url: String) {
         // Create an open with app intent with `ACTION_VIEW`.
@@ -5868,6 +6209,9 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
 
         // Go back.
         currentWebView!!.goBack()
+
+        // Update the URL edit text after a delay.
+        updateUrlEditTextAfterDelay()
     }
 
     private fun sanitizeUrl(urlString: String): String {
@@ -5910,16 +6254,16 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
         // Stop the swipe to refresh indicator if it is running
         swipeRefreshLayout.isRefreshing = false
 
-        // Get the WebView tab fragment.
-        val webViewTabFragment = webViewStateAdapter!!.getPageFragment(pageNumber)
+        // Try to set the current WebView.  This will fail if the WebView has not yet been populated.
+        try {
+            // Get the WebView tab fragment.
+            val webViewTabFragment = webViewStateAdapter!!.getPageFragment(pageNumber)
 
-        // Get the fragment view.
-        val webViewFragmentView = webViewTabFragment.view
+            // Get the fragment view.
+            val webViewFragmentView = webViewTabFragment.view
 
-        // Set the current WebView if the fragment view is not null.
-        if (webViewFragmentView != null) {  // The fragment has been populated.
             // Store the current WebView.
-            currentWebView = webViewFragmentView.findViewById(R.id.nestedscroll_webview)
+            currentWebView = webViewFragmentView!!.findViewById(R.id.nestedscroll_webview)
 
             // Update the status of swipe to refresh.
             if (currentWebView!!.swipeToRefresh) {  // Swipe to refresh is enabled.
@@ -5979,8 +6323,7 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
                 // Remove any background on the URL relative layout.
                 urlRelativeLayout.background = AppCompatResources.getDrawable(this, R.color.transparent)
             }
-        } else if ((pageNumber == savedTabPosition) || (pageNumber >= (webViewStateAdapter!!.itemCount - 1))) {  // The tab has not been populated yet.
-            //  Try again in 100 milliseconds if the app is being restored or the a new tab has been added (the last tab).
+        }  catch (exception: Exception) {  //  Try again in 10 milliseconds if the WebView has not yet been populated.
             // Create a handler to set the current WebView.
             val setCurrentWebViewHandler = Handler(Looper.getMainLooper())
 
@@ -5990,8 +6333,8 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
                 setCurrentWebView(pageNumber)
             }
 
-            // Try setting the current WebView again after 100 milliseconds.
-            setCurrentWebViewHandler.postDelayed(setCurrentWebWebRunnable, 100)
+            // Try setting the current WebView again after 10 milliseconds.
+            setCurrentWebViewHandler.postDelayed(setCurrentWebWebRunnable, 10)
         }
     }
 
@@ -6087,4 +6430,22 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
                 invalidateOptionsMenu()
         }
     }
+
+    fun updateUrlEditTextAfterDelay() {
+        // Create a handler to update the URL edit box.
+        val urlEditTextUpdateHandler = Handler(Looper.getMainLooper())
+
+        // Create a runnable to update the URL edit box.
+        val urlEditTextUpdateRunnable = Runnable {
+            // Update the URL edit text.
+            urlEditText.setText(currentWebView!!.url)
+
+            // Disable the wide viewport if the source is being viewed.
+            if (currentWebView!!.url!!.startsWith("view-source:"))
+                currentWebView!!.settings.useWideViewPort = false
+        }
+
+        // Update the URL edit text after 50 milliseconds, so that the WebView has enough time to navigate to the new URL.
+        urlEditTextUpdateHandler.postDelayed(urlEditTextUpdateRunnable, 50)
+    }
 }