]> gitweb.stoutner.com Git - PrivacyBrowserAndroid.git/blobdiff - app/src/main/java/com/stoutner/privacybrowser/fragments/AboutVersionFragment.kt
Replace `Loading...` and favorite icon on tab after download dialog opens. https...
[PrivacyBrowserAndroid.git] / app / src / main / java / com / stoutner / privacybrowser / fragments / AboutVersionFragment.kt
index c4c522741f892e56f80ee0930bc4a7a8b9856d14..eeaae384d561ec956049a0241fa796ddf379729b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright © 2016-2022 Soren Stoutner <soren@stoutner.com>.
+ * Copyright 2016-2023 Soren Stoutner <soren@stoutner.com>.
  *
  * This file is part of Privacy Browser Android <https://www.stoutner.com/privacy-browser-android>.
  *
@@ -27,7 +27,6 @@ import android.content.ClipboardManager
 import android.content.Context
 import android.content.Intent
 import android.content.pm.PackageManager
-import android.net.Uri
 import android.os.Build
 import android.os.Bundle
 import android.os.Handler
@@ -42,7 +41,6 @@ import android.view.MenuInflater
 import android.view.MenuItem
 import android.view.View
 import android.view.ViewGroup
-import android.webkit.WebView
 import android.widget.TextView
 
 import androidx.activity.result.contract.ActivityResultContracts
@@ -51,9 +49,14 @@ import androidx.webkit.WebViewCompat
 
 import com.google.android.material.snackbar.Snackbar
 
-import com.stoutner.privacybrowser.R
 import com.stoutner.privacybrowser.BuildConfig
-import com.stoutner.privacybrowser.asynctasks.SaveAboutVersionImage
+import com.stoutner.privacybrowser.R
+import com.stoutner.privacybrowser.coroutines.SaveAboutVersionImageCoroutine
+
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
 
 import java.io.ByteArrayInputStream
 import java.io.InputStream
@@ -68,7 +71,8 @@ import java.text.NumberFormat
 import kotlin.text.StringBuilder
 
 // Define the class constants.
-private const val BLOCKLIST_VERSIONS = "blocklist_versions"
+private const val FILTERLISTS_VERSIONS = "A"
+private const val SCROLL_Y = "B"
 private const val MEBIBYTE = 1048576
 
 class AboutVersionFragment : Fragment() {
@@ -76,72 +80,72 @@ class AboutVersionFragment : Fragment() {
     private var updateMemoryUsageBoolean = true
 
     // Declare the class variables.
-    private lateinit var blocklistVersions: Array<String>
     private lateinit var aboutVersionLayout: View
-    private lateinit var appConsumedMemoryLabel: String
+    private lateinit var activityManager: ActivityManager
     private lateinit var appAvailableMemoryLabel: String
-    private lateinit var appTotalMemoryLabel: String
+    private lateinit var appConsumedMemoryLabel: String
     private lateinit var appMaximumMemoryLabel: String
-    private lateinit var systemConsumedMemoryLabel: String
-    private lateinit var systemAvailableMemoryLabel: String
-    private lateinit var systemTotalMemoryLabel: String
-    private lateinit var runtime: Runtime
-    private lateinit var activityManager: ActivityManager
+    private lateinit var appTotalMemoryLabel: String
+    private lateinit var blueColorSpan: ForegroundColorSpan
+    private lateinit var filterListsVersions: Array<String>
     private lateinit var memoryInfo: ActivityManager.MemoryInfo
     private lateinit var numberFormat: NumberFormat
-    private lateinit var blueColorSpan: ForegroundColorSpan
+    private lateinit var runtime: Runtime
+    private lateinit var systemAvailableMemoryLabel: String
+    private lateinit var systemConsumedMemoryLabel: String
+    private lateinit var systemTotalMemoryLabel: String
 
     // Declare the class views.
-    private lateinit var privacyBrowserTextView: TextView
-    private lateinit var versionTextView: TextView
-    private lateinit var hardwareTextView: TextView
-    private lateinit var brandTextView: TextView
-    private lateinit var manufacturerTextView: TextView
-    private lateinit var modelTextView: TextView
-    private lateinit var deviceTextView: TextView
-    private lateinit var bootloaderTextView: TextView
-    private lateinit var radioTextView: TextView
-    private lateinit var softwareTextView: TextView
     private lateinit var androidTextView: TextView
-    private lateinit var securityPatchTextView: TextView
-    private lateinit var buildTextView: TextView
-    private lateinit var kernelTextView: TextView
-    private lateinit var webViewProviderTextView: TextView
-    private lateinit var webViewVersionTextView: TextView
-    private lateinit var orbotTextView: TextView
-    private lateinit var i2pTextView: TextView
-    private lateinit var openKeychainTextView: TextView
-    private lateinit var memoryUsageTextView: TextView
-    private lateinit var appConsumedMemoryTextView: TextView
     private lateinit var appAvailableMemoryTextView: TextView
-    private lateinit var appTotalMemoryTextView: TextView
+    private lateinit var appConsumedMemoryTextView: TextView
     private lateinit var appMaximumMemoryTextView: TextView
-    private lateinit var systemConsumedMemoryTextView: TextView
-    private lateinit var systemAvailableMemoryTextView: TextView
-    private lateinit var systemTotalMemoryTextView: TextView
-    private lateinit var blocklistsTextView: TextView
+    private lateinit var appTotalMemoryTextView: TextView
+    private lateinit var brandTextView: TextView
+    private lateinit var bootloaderTextView: TextView
+    private lateinit var certificateEndDateTextView: TextView
+    private lateinit var certificateIssuerDnTextView: TextView
+    private lateinit var certificateSerialNumberTextView: TextView
+    private lateinit var certificateSignatureAlgorithmTextView: TextView
+    private lateinit var certificateStartDateTextView: TextView
+    private lateinit var certificateSubjectDnTextView: TextView
+    private lateinit var certificateVersionTextView: TextView
+    private lateinit var buildTextView: TextView
+    private lateinit var deviceTextView: TextView
     private lateinit var easyListTextView: TextView
     private lateinit var easyPrivacyTextView: TextView
     private lateinit var fanboyAnnoyanceTextView: TextView
     private lateinit var fanboySocialTextView: TextView
+    private lateinit var filterListsTextView: TextView
+    private lateinit var hardwareTextView: TextView
+    private lateinit var i2pTextView: TextView
+    private lateinit var kernelTextView: TextView
+    private lateinit var manufacturerTextView: TextView
+    private lateinit var memoryUsageTextView: TextView
+    private lateinit var modelTextView: TextView
+    private lateinit var openKeychainTextView: TextView
+    private lateinit var orbotTextView: TextView
+    private lateinit var packageSignatureTextView: TextView
+    private lateinit var privacyBrowserTextView: TextView
+    private lateinit var radioTextView: TextView
+    private lateinit var securityPatchTextView: TextView
+    private lateinit var softwareTextView: TextView
+    private lateinit var systemAvailableMemoryTextView: TextView
+    private lateinit var systemConsumedMemoryTextView: TextView
+    private lateinit var systemTotalMemoryTextView: TextView
+    private lateinit var versionTextView: TextView
     private lateinit var ultraListTextView: TextView
     private lateinit var ultraPrivacyTextView: TextView
-    private lateinit var packageSignatureTextView: TextView
-    private lateinit var certificateIssuerDnTextView: TextView
-    private lateinit var certificateSubjectDnTextView: TextView
-    private lateinit var certificateStartDateTextView: TextView
-    private lateinit var certificateEndDateTextView: TextView
-    private lateinit var certificateVersionTextView: TextView
-    private lateinit var certificateSerialNumberTextView: TextView
-    private lateinit var certificateSignatureAlgorithmTextView: TextView
+    private lateinit var webViewProviderTextView: TextView
+    private lateinit var webViewVersionTextView: TextView
 
     companion object {
-        fun createTab(blocklistVersions: Array<String>): AboutVersionFragment {
+        fun createTab(filterListsVersions: Array<String>): AboutVersionFragment {
             // Create an arguments bundle.
             val argumentsBundle = Bundle()
 
             // Store the arguments in the bundle.
-            argumentsBundle.putStringArray(BLOCKLIST_VERSIONS, blocklistVersions)
+            argumentsBundle.putStringArray(FILTERLISTS_VERSIONS, filterListsVersions)
 
             // Create a new instance of the tab fragment.
             val aboutVersionFragment = AboutVersionFragment()
@@ -155,56 +159,59 @@ class AboutVersionFragment : Fragment() {
     }
 
     // Define the save about version text activity result launcher.  It must be defined before `onCreate()` is run or the app will crash.
-    private val saveAboutVersionTextActivityResultLauncher = registerForActivityResult(ActivityResultContracts.CreateDocument("text/plain")) { fileUri: Uri? ->
+    private val saveAboutVersionTextActivityResultLauncher = registerForActivityResult(ActivityResultContracts.CreateDocument("text/plain")) { fileUri ->
         // Only save the file if the URI is not null, which happens if the user exited the file picker by pressing back.
         if (fileUri != null) {
-            try {
-                // Get the about version string.
-                val aboutVersionString = getAboutVersionString()
+            // Initialize the file name string from the file URI last path segment.
+            var fileNameString = fileUri.lastPathSegment
 
-                // Open an output stream.
-                val outputStream = requireActivity().contentResolver.openOutputStream(fileUri)!!
+            // Query the exact file name if the API >= 26.
+            if (Build.VERSION.SDK_INT >= 26) {
+                // Get a cursor from the content resolver.
+                val contentResolverCursor = requireActivity().contentResolver.query(fileUri, null, null, null)!!
 
-                // Write the about version string to the output stream.
-                outputStream.write(aboutVersionString.toByteArray(StandardCharsets.UTF_8))
+                // Move to the first row.
+                contentResolverCursor.moveToFirst()
 
-                // Close the output stream.
-                outputStream.close()
+                // Get the file name from the cursor.
+                fileNameString = contentResolverCursor.getString(contentResolverCursor.getColumnIndexOrThrow(OpenableColumns.DISPLAY_NAME))
 
-                // Initialize the file name string from the file URI last path segment.
-                var fileNameString = fileUri.lastPathSegment
+                // Close the cursor.
+                contentResolverCursor.close()
+            }
 
-                // Query the exact file name if the API >= 26.
-                if (Build.VERSION.SDK_INT >= 26) {
-                    // Get a cursor from the content resolver.
-                    val contentResolverCursor = requireActivity().contentResolver.query(fileUri, null, null, null)!!
+            try {
+                // Get the about version string.
+                val aboutVersionString = getAboutVersionString()
 
-                    // Move to the first row.
-                    contentResolverCursor.moveToFirst()
+                // Open an output stream.
+                val outputStream = requireActivity().contentResolver.openOutputStream(fileUri)!!
 
-                    // Get the file name from the cursor.
-                    fileNameString = contentResolverCursor.getString(contentResolverCursor.getColumnIndexOrThrow(OpenableColumns.DISPLAY_NAME))
+                // Save about version using a coroutine with Dispatchers.IO.
+                CoroutineScope(Dispatchers.Main).launch {
+                    withContext(Dispatchers.IO) {
+                        // Write the about version string to the output stream.
+                        outputStream.write(aboutVersionString.toByteArray(StandardCharsets.UTF_8))
 
-                    // Close the cursor.
-                    contentResolverCursor.close()
+                        // Close the output stream.
+                        outputStream.close()
+                    }
                 }
 
                 // Display a snackbar with the saved logcat information.
                 Snackbar.make(aboutVersionLayout, getString(R.string.saved, fileNameString), Snackbar.LENGTH_SHORT).show()
             } catch (exception: Exception) {
                 // Display a snackbar with the error message.
-                Snackbar.make(aboutVersionLayout, getString(R.string.error_saving_file) + "  " + exception.toString(), Snackbar.LENGTH_INDEFINITE).show()
+                Snackbar.make(aboutVersionLayout, getString(R.string.error_saving_file, fileNameString, exception.toString()), Snackbar.LENGTH_INDEFINITE).show()
             }
         }
     }
 
     // Define the save about version image activity result launcher.  It must be defined before `onCreate()` is run or the app will crash.
-    private val saveAboutVersionImageActivityResultLauncher = registerForActivityResult(ActivityResultContracts.CreateDocument("image/png")) { fileUri: Uri? ->
-        // Only save the file if the URI is not null, which happens if the user exited the file picker by pressing back.
-        if (fileUri != null) {
-            // Save the about version image.
-            SaveAboutVersionImage(requireActivity(), fileUri, aboutVersionLayout.findViewById(R.id.about_version_linearlayout)).execute()
-        }
+    private val saveAboutVersionImageActivityResultLauncher = registerForActivityResult(ActivityResultContracts.CreateDocument("image/png")) { fileUri ->
+        // Save the file if the URI is not null, which happens if the user exits the file picker by pressing back.
+        if (fileUri != null)
+            SaveAboutVersionImageCoroutine.saveImage(requireActivity(), fileUri, aboutVersionLayout.findViewById(R.id.about_version_linearlayout))
     }
 
     override fun onCreate(savedInstanceState: Bundle?) {
@@ -212,7 +219,7 @@ class AboutVersionFragment : Fragment() {
         super.onCreate(savedInstanceState)
 
         // Store the arguments in class variables.
-        blocklistVersions = requireArguments().getStringArray(BLOCKLIST_VERSIONS)!!
+        filterListsVersions = requireArguments().getStringArray(FILTERLISTS_VERSIONS)!!
 
         // Enable the options menu for this fragment.
         setHasOptionsMenu(true)
@@ -250,7 +257,7 @@ class AboutVersionFragment : Fragment() {
         systemConsumedMemoryTextView = aboutVersionLayout.findViewById(R.id.system_consumed_memory)
         systemAvailableMemoryTextView = aboutVersionLayout.findViewById(R.id.system_available_memory)
         systemTotalMemoryTextView = aboutVersionLayout.findViewById(R.id.system_total_memory)
-        blocklistsTextView = aboutVersionLayout.findViewById(R.id.blocklists)
+        filterListsTextView = aboutVersionLayout.findViewById(R.id.filterlists)
         easyListTextView = aboutVersionLayout.findViewById(R.id.easylist)
         easyPrivacyTextView = aboutVersionLayout.findViewById(R.id.easyprivacy)
         fanboyAnnoyanceTextView = aboutVersionLayout.findViewById(R.id.fanboy_annoyance)
@@ -267,42 +274,41 @@ class AboutVersionFragment : Fragment() {
         certificateSignatureAlgorithmTextView = aboutVersionLayout.findViewById(R.id.certificate_signature_algorithm)
 
         // Setup the labels.
-        val version = getString(R.string.version) + " " + BuildConfig.VERSION_NAME + " (" + getString(R.string.version_code) + " " + BuildConfig.VERSION_CODE + ")"
-        val brandLabel = getString(R.string.brand) + "  "
-        val manufacturerLabel = getString(R.string.manufacturer) + "  "
-        val modelLabel = getString(R.string.model) + "  "
-        val deviceLabel = getString(R.string.device) + "  "
-        val bootloaderLabel = getString(R.string.bootloader) + "  "
-        val androidLabel = getString(R.string.android) + "  "
-        val buildLabel = getString(R.string.build) + "  "
-        val kernelLabel = getString(R.string.kernel) + "  "
-        val webViewVersionLabel = getString(R.string.webview_version) + "  "
-        appConsumedMemoryLabel = getString(R.string.app_consumed_memory) + "  "
-        appAvailableMemoryLabel = getString(R.string.app_available_memory) + "  "
-        appTotalMemoryLabel = getString(R.string.app_total_memory) + "  "
-        appMaximumMemoryLabel = getString(R.string.app_maximum_memory) + "  "
-        systemConsumedMemoryLabel = getString(R.string.system_consumed_memory) + "  "
-        systemAvailableMemoryLabel = getString(R.string.system_available_memory) + "  "
-        systemTotalMemoryLabel = getString(R.string.system_total_memory) + "  "
-        val easyListLabel = getString(R.string.easylist_label) + "  "
-        val easyPrivacyLabel = getString(R.string.easyprivacy_label) + "  "
-        val fanboyAnnoyanceLabel = getString(R.string.fanboys_annoyance_label) + "  "
-        val fanboySocialLabel = getString(R.string.fanboys_social_label) + "  "
-        val ultraListLabel = getString(R.string.ultralist_label) + "  "
-        val ultraPrivacyLabel = getString(R.string.ultraprivacy_label) + "  "
-        val issuerDNLabel = getString(R.string.issuer_dn) + "  "
-        val subjectDNLabel = getString(R.string.subject_dn) + "  "
-        val startDateLabel = getString(R.string.start_date) + "  "
-        val endDateLabel = getString(R.string.end_date) + "  "
-        val certificateVersionLabel = getString(R.string.certificate_version) + "  "
-        val serialNumberLabel = getString(R.string.serial_number) + "  "
-        val signatureAlgorithmLabel = getString(R.string.signature_algorithm) + "  "
-
-        // The WebView layout is only used to get the default user agent from `bare_webview`.  It is not used to render content on the screen.
-        // Once the minimum API >= 26 this can be accomplished with the WebView package info.
-        val webViewLayout = layoutInflater.inflate(R.layout.bare_webview, container, false)
-        val tabLayoutWebView = webViewLayout.findViewById<WebView>(R.id.bare_webview)
-        val userAgentString = tabLayoutWebView.settings.userAgentString
+        val version = getString(R.string.version_code, BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE)
+        val brandLabel = getString(R.string.brand)
+        val manufacturerLabel = getString(R.string.manufacturer)
+        val modelLabel = getString(R.string.model)
+        val deviceLabel = getString(R.string.device)
+        val bootloaderLabel = getString(R.string.bootloader)
+        val androidLabel = getString(R.string.android)
+        val securityPatchLabel = getString(R.string.security_patch)
+        val buildLabel = getString(R.string.build)
+        val kernelLabel = getString(R.string.kernel)
+        val webViewProviderLabel = getString(R.string.webview_provider)
+        val webViewVersionLabel = getString(R.string.webview_version)
+        appConsumedMemoryLabel = getString(R.string.app_consumed_memory)
+        appAvailableMemoryLabel = getString(R.string.app_available_memory)
+        appTotalMemoryLabel = getString(R.string.app_total_memory)
+        appMaximumMemoryLabel = getString(R.string.app_maximum_memory)
+        systemConsumedMemoryLabel = getString(R.string.system_consumed_memory)
+        systemAvailableMemoryLabel = getString(R.string.system_available_memory)
+        systemTotalMemoryLabel = getString(R.string.system_total_memory)
+        val easyListLabel = getString(R.string.easylist_label)
+        val easyPrivacyLabel = getString(R.string.easyprivacy_label)
+        val fanboyAnnoyanceLabel = getString(R.string.fanboys_annoyance_label)
+        val fanboySocialLabel = getString(R.string.fanboys_social_label)
+        val ultraListLabel = getString(R.string.ultralist_label)
+        val ultraPrivacyLabel = getString(R.string.ultraprivacy_label)
+        val issuerDNLabel = getString(R.string.issuer_dn)
+        val subjectDNLabel = getString(R.string.subject_dn)
+        val startDateLabel = getString(R.string.start_date)
+        val endDateLabel = getString(R.string.end_date)
+        val certificateVersionLabel = getString(R.string.certificate_version)
+        val serialNumberLabel = getString(R.string.serial_number)
+        val signatureAlgorithmLabel = getString(R.string.signature_algorithm)
+
+        // Get the current WebView package info.  This can be replaced by the direct call once the minimum API >= 26.  <https://developer.android.com/reference/android/webkit/WebView#getCurrentWebViewPackage()>
+        val webViewPackageInfo = WebViewCompat.getCurrentWebViewPackage(requireContext())!!
 
         // Get the device's information and store it in strings.
         val brand = Build.BRAND
@@ -311,17 +317,16 @@ class AboutVersionFragment : Fragment() {
         val device = Build.DEVICE
         val bootloader = Build.BOOTLOADER
         val radio = Build.getRadioVersion()
-        val android = Build.VERSION.RELEASE + " (" + getString(R.string.api) + " " + Build.VERSION.SDK_INT + ")"
+        val android = getString(R.string.api, Build.VERSION.RELEASE, Build.VERSION.SDK_INT)
+        val securityPatch = Build.VERSION.SECURITY_PATCH
         val build = Build.DISPLAY
         val kernel = System.getProperty("os.version")
-
-        // Get the WebView version, selecting the substring that begins after `Chrome/` and goes until the next ` `.
-        val webView = userAgentString.substring(userAgentString.indexOf("Chrome/") + 7, userAgentString.indexOf(" ", userAgentString.indexOf("Chrome/")))
+        val webViewPackageName = webViewPackageInfo.packageName
+        val webViewVersion = webViewPackageInfo.versionName
 
         // Get the Orbot version name if Orbot is installed.
         val orbot: String = try {
-            // Store the version name.  The newer `getPackageInfo()` may be used once the minimum API >= 33.
-            @Suppress("DEPRECATION")
+            // Store the version name.
             requireContext().packageManager.getPackageInfo("org.torproject.android", 0).versionName
         } catch (exception: PackageManager.NameNotFoundException) {  // Orbot is not installed.
             // Store an empty string.
@@ -330,14 +335,12 @@ class AboutVersionFragment : Fragment() {
 
         // Get the I2P version name if I2P is installed.
         val i2p: String = try {
-            // Check to see if the F-Droid flavor is installed.  The newer `getPackageInfo()` may be used once the minimum API >= 33.
-            @Suppress("DEPRECATION")
-            requireContext().packageManager.getPackageInfo("net.i2p.android.router", 0).versionName + " " + requireContext().getString(R.string.fdroid_flavor)
+            // Check to see if the F-Droid flavor is installed.
+            getString(R.string.fdroid_flavor, requireContext().packageManager.getPackageInfo("net.i2p.android.router", 0).versionName)
         } catch (exception: PackageManager.NameNotFoundException) {  // The F-Droid flavor is not installed.
             try {
-                // Check to see if the F-Droid flavor is installed.  The newer `getPackageInfo()` may be used once the minimum API >= 33.
-                @Suppress("DEPRECATION")
-                requireContext().packageManager.getPackageInfo("net.i2p.android", 0).versionName + " " + requireContext().getString(R.string.google_play_flavor)
+                // Check to see if the F-Droid flavor is installed.
+                getString(R.string.google_play_flavor, requireContext().packageManager.getPackageInfo("net.i2p.android", 0).versionName)
             } catch (exception: PackageManager.NameNotFoundException) {  // The Google Play flavor is not installed either.
                 // Store an empty string.
                 ""
@@ -346,8 +349,7 @@ class AboutVersionFragment : Fragment() {
 
         // Get the OpenKeychain version name if it is installed.
         val openKeychain: String = try {
-            // Store the version name.  The newer `getPackageInfo()` may be used once the minimum API >= 33.
-            @Suppress("DEPRECATION")
+            // Store the version name.
             requireContext().packageManager.getPackageInfo("org.sufficientlysecure.keychain", 0).versionName
         } catch (exception: PackageManager.NameNotFoundException) {  // OpenKeychain is not installed.
             // Store an empty string.
@@ -361,15 +363,17 @@ class AboutVersionFragment : Fragment() {
         val deviceStringBuilder = SpannableStringBuilder(deviceLabel + device)
         val bootloaderStringBuilder = SpannableStringBuilder(bootloaderLabel + bootloader)
         val androidStringBuilder = SpannableStringBuilder(androidLabel + android)
+        val securityPatchStringBuilder = SpannableStringBuilder(securityPatchLabel + securityPatch)
         val buildStringBuilder = SpannableStringBuilder(buildLabel + build)
         val kernelStringBuilder = SpannableStringBuilder(kernelLabel + kernel)
-        val webViewVersionStringBuilder = SpannableStringBuilder(webViewVersionLabel + webView)
-        val easyListStringBuilder = SpannableStringBuilder(easyListLabel + blocklistVersions[0])
-        val easyPrivacyStringBuilder = SpannableStringBuilder(easyPrivacyLabel + blocklistVersions[1])
-        val fanboyAnnoyanceStringBuilder = SpannableStringBuilder(fanboyAnnoyanceLabel + blocklistVersions[2])
-        val fanboySocialStringBuilder = SpannableStringBuilder(fanboySocialLabel + blocklistVersions[3])
-        val ultraListStringBuilder = SpannableStringBuilder(ultraListLabel + blocklistVersions[4])
-        val ultraPrivacyStringBuilder = SpannableStringBuilder(ultraPrivacyLabel + blocklistVersions[5])
+        val webViewProviderStringBuilder = SpannableStringBuilder(webViewProviderLabel + webViewPackageName)
+        val webViewVersionStringBuilder = SpannableStringBuilder(webViewVersionLabel + webViewVersion)
+        val easyListStringBuilder = SpannableStringBuilder(easyListLabel + filterListsVersions[0])
+        val easyPrivacyStringBuilder = SpannableStringBuilder(easyPrivacyLabel + filterListsVersions[1])
+        val fanboyAnnoyanceStringBuilder = SpannableStringBuilder(fanboyAnnoyanceLabel + filterListsVersions[2])
+        val fanboySocialStringBuilder = SpannableStringBuilder(fanboySocialLabel + filterListsVersions[3])
+        val ultraListStringBuilder = SpannableStringBuilder(ultraListLabel + filterListsVersions[4])
+        val ultraPrivacyStringBuilder = SpannableStringBuilder(ultraPrivacyLabel + filterListsVersions[5])
 
         // Set the blue color span according to the theme.  The deprecated `getColor()` must be used until the minimum API >= 23.
         blueColorSpan = ForegroundColorSpan(requireContext().getColor(R.color.alt_blue_text))
@@ -381,8 +385,10 @@ class AboutVersionFragment : Fragment() {
         deviceStringBuilder.setSpan(blueColorSpan, deviceLabel.length, deviceStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
         bootloaderStringBuilder.setSpan(blueColorSpan, bootloaderLabel.length, bootloaderStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
         androidStringBuilder.setSpan(blueColorSpan, androidLabel.length, androidStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
+        securityPatchStringBuilder.setSpan(blueColorSpan, securityPatchLabel.length, securityPatchStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
         buildStringBuilder.setSpan(blueColorSpan, buildLabel.length, buildStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
         kernelStringBuilder.setSpan(blueColorSpan, kernelLabel.length, kernelStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
+        webViewProviderStringBuilder.setSpan(blueColorSpan, webViewProviderLabel.length, webViewProviderStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
         webViewVersionStringBuilder.setSpan(blueColorSpan, webViewVersionLabel.length, webViewVersionStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
         easyListStringBuilder.setSpan(blueColorSpan, easyListLabel.length, easyListStringBuilder.length, Spanned.SPAN_INCLUSIVE_EXCLUSIVE)
         easyPrivacyStringBuilder.setSpan(blueColorSpan, easyPrivacyLabel.length, easyPrivacyStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
@@ -399,8 +405,10 @@ class AboutVersionFragment : Fragment() {
         deviceTextView.text = deviceStringBuilder
         bootloaderTextView.text = bootloaderStringBuilder
         androidTextView.text = androidStringBuilder
+        securityPatchTextView.text = securityPatchStringBuilder
         buildTextView.text = buildStringBuilder
         kernelTextView.text = kernelStringBuilder
+        webViewProviderTextView.text = webViewProviderStringBuilder
         webViewVersionTextView.text = webViewVersionStringBuilder
         easyListTextView.text = easyListStringBuilder
         easyPrivacyTextView.text = easyPrivacyStringBuilder
@@ -413,7 +421,7 @@ class AboutVersionFragment : Fragment() {
         // Null must be checked because some Samsung tablets report a null value for the radio instead of an empty string.  Grrrr.  <https://redmine.stoutner.com/issues/701>
         if (radio != null && radio.isNotEmpty()) {
             // Setup the label.
-            val radioLabel = getString(R.string.radio) + "  "
+            val radioLabel = getString(R.string.radio)
 
             // Create a spannable string builder.
             val radioStringBuilder = SpannableStringBuilder(radioLabel + radio)
@@ -428,43 +436,10 @@ class AboutVersionFragment : Fragment() {
             radioTextView.visibility = View.GONE
         }
 
-        // Setup the label.
-        val securityPatchLabel = getString(R.string.security_patch) + "  "
-
-        // Get the security patch version.
-        val securityPatch = Build.VERSION.SECURITY_PATCH
-
-        // Create a spannable string builder.
-        val securityPatchStringBuilder = SpannableStringBuilder(securityPatchLabel + securityPatch)
-
-        // Set the span to display the security patch version in blue.
-        securityPatchStringBuilder.setSpan(blueColorSpan, securityPatchLabel.length, securityPatchStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
-
-        // Display the string in the text view.
-        securityPatchTextView.text = securityPatchStringBuilder
-
-        // Create the WebView provider label.
-        val webViewProviderLabel = getString(R.string.webview_provider) + "  "
-
-        // Get the current WebView package info.
-        val webViewPackageInfo = WebViewCompat.getCurrentWebViewPackage(requireContext())!!
-
-        // Get the WebView provider name.
-        val webViewPackageName = webViewPackageInfo.packageName
-
-        // Create the spannable string builder.
-        val webViewProviderStringBuilder = SpannableStringBuilder(webViewProviderLabel + webViewPackageName)
-
-        // Apply the coloration.
-        webViewProviderStringBuilder.setSpan(blueColorSpan, webViewProviderLabel.length, webViewProviderStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
-
-        // Display the WebView provider.
-        webViewProviderTextView.text = webViewProviderStringBuilder
-
         // Only populate the Orbot text view if it is installed.
         if (orbot.isNotEmpty()) {
             // Setup the label.
-            val orbotLabel = getString(R.string.orbot) + "  "
+            val orbotLabel = getString(R.string.orbot)
 
             // Create a spannable string builder.
             val orbotStringBuilder = SpannableStringBuilder(orbotLabel + orbot)
@@ -482,7 +457,7 @@ class AboutVersionFragment : Fragment() {
         // Only populate the I2P text view if it is installed.
         if (i2p.isNotEmpty()) {
             // Setup the label.
-            val i2pLabel = getString(R.string.i2p) + "  "
+            val i2pLabel = getString(R.string.i2p)
 
             // Create a spannable string builder.
             val i2pStringBuilder = SpannableStringBuilder(i2pLabel + i2p)
@@ -500,7 +475,7 @@ class AboutVersionFragment : Fragment() {
         // Only populate the OpenKeychain text view if it is installed.
         if (openKeychain.isNotEmpty()) {
             // Setup the label.
-            val openKeychainLabel = getString(R.string.openkeychain) + "  "
+            val openKeychainLabel = getString(R.string.openkeychain)
 
             // Create a spannable string builder.
             val openKeychainStringBuilder = SpannableStringBuilder(openKeychainLabel + openKeychain)
@@ -598,8 +573,7 @@ class AboutVersionFragment : Fragment() {
         // Scroll the tab if the saved instance state is not null.
         if (savedInstanceState != null) {
             aboutVersionLayout.post {
-                aboutVersionLayout.scrollX = savedInstanceState.getInt("scroll_x")
-                aboutVersionLayout.scrollY = savedInstanceState.getInt("scroll_y")
+                aboutVersionLayout.scrollY = savedInstanceState.getInt(SCROLL_Y)
             }
         }
 
@@ -625,14 +599,15 @@ class AboutVersionFragment : Fragment() {
                 // Get a handle for the clipboard manager.
                 val clipboardManager = (requireActivity().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager)
 
-                // Save the about version string in a clip data.
+                // Place the about version string in a clip data.
                 val aboutVersionClipData = ClipData.newPlainText(getString(R.string.about), aboutVersionString)
 
                 // Place the clip data on the clipboard.
                 clipboardManager.setPrimaryClip(aboutVersionClipData)
 
-                // Display a snackbar.
-                Snackbar.make(aboutVersionLayout, R.string.version_info_copied, Snackbar.LENGTH_SHORT).show()
+                // Display a snackbar if the API <= 32 (Android 12L).  Beginning in Android 13 the OS displays a notification that covers up the snackbar.
+                if (Build.VERSION.SDK_INT <= 32)
+                    Snackbar.make(aboutVersionLayout, R.string.version_info_copied, Snackbar.LENGTH_SHORT).show()
 
                 // Consume the event.
                 return true
@@ -642,20 +617,20 @@ class AboutVersionFragment : Fragment() {
                 // Get the about version string.
                 val aboutString = getAboutVersionString()
 
-                // Create an email intent.
-                val emailIntent = Intent(Intent.ACTION_SEND)
+                // Create a share intent.
+                val shareIntent = Intent(Intent.ACTION_SEND)
 
                 // Add the about version string to the intent.
-                emailIntent.putExtra(Intent.EXTRA_TEXT, aboutString)
+                shareIntent.putExtra(Intent.EXTRA_TEXT, aboutString)
 
                 // Set the MIME type.
-                emailIntent.type = "text/plain"
+                shareIntent.type = "text/plain"
 
                 // Set the intent to open in a new task.
-                emailIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+                shareIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
 
                 // Make it so.
-                startActivity(Intent.createChooser(emailIntent, getString(R.string.share)))
+                startActivity(Intent.createChooser(shareIntent, getString(R.string.share)))
 
                 // Consume the event.
                 return true
@@ -676,6 +651,7 @@ class AboutVersionFragment : Fragment() {
                 // Consume the event.
                 return true
             }
+
             else -> {  // The home button was selected.
                 // Run the parents class on return.
                 return super.onOptionsItemSelected(menuItem)
@@ -687,9 +663,8 @@ class AboutVersionFragment : Fragment() {
         // Run the default commands.
         super.onSaveInstanceState(savedInstanceState)
 
-        // Save the scroll positions.
-        savedInstanceState.putInt("scroll_x", aboutVersionLayout.scrollX)
-        savedInstanceState.putInt("scroll_y", aboutVersionLayout.scrollY)
+        // Save the scroll position.
+        savedInstanceState.putInt(SCROLL_Y, aboutVersionLayout.scrollY)
     }
 
     override fun onPause() {
@@ -708,7 +683,7 @@ class AboutVersionFragment : Fragment() {
         updateMemoryUsageBoolean = true
     }
 
-    fun updateMemoryUsage(activity: Activity) {
+    private fun updateMemoryUsage(activity: Activity) {
         try {
             // Update the memory usage if enabled.
             if (updateMemoryUsageBoolean) {
@@ -789,7 +764,7 @@ class AboutVersionFragment : Fragment() {
         }
     }
 
-    fun getAboutVersionString(): String {
+    private fun getAboutVersionString(): String {
         // Initialize an about version string builder.
         val aboutVersionStringBuilder = StringBuilder()
 
@@ -862,7 +837,7 @@ class AboutVersionFragment : Fragment() {
         aboutVersionStringBuilder.append("\n")
         aboutVersionStringBuilder.append(systemTotalMemoryTextView.text)
         aboutVersionStringBuilder.append("\n\n")
-        aboutVersionStringBuilder.append(blocklistsTextView.text)
+        aboutVersionStringBuilder.append(filterListsTextView.text)
         aboutVersionStringBuilder.append("\n")
         aboutVersionStringBuilder.append(easyListTextView.text)
         aboutVersionStringBuilder.append("\n")
@@ -895,4 +870,4 @@ class AboutVersionFragment : Fragment() {
         // Return the string.
         return aboutVersionStringBuilder.toString()
     }
-}
\ No newline at end of file
+}