]> gitweb.stoutner.com Git - PrivacyCell.git/blobdiff - app/src/main/java/com/stoutner/privacycell/activities/PrivacyCellActivity.kt
Release 1.11.
[PrivacyCell.git] / app / src / main / java / com / stoutner / privacycell / activities / PrivacyCellActivity.kt
index 296a95290ffbe6e1d4836dfcb842afb992ea85f8..3b89b88b4377b72963e6e8d0af7331ebe5f85446 100644 (file)
@@ -1,32 +1,38 @@
-/*
- * Copyright © 2021 Soren Stoutner <soren@stoutner.com>.
+/* SPDX-License-Identifier: GPL-3.0-or-later
+ * SPDX-FileCopyrightText: 2021-2022, 2025 Soren Stoutner <soren@stoutner.com>
  *
- * This file is part of Privacy Cell <https://www.stoutner.com/privacy-cell>.
+ * This file is part of Privacy Cell <https://www.stoutner.com/privacy-cell/>.
  *
- * Privacy Cell is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
+ * This program is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later
+ * version.
  *
- * Privacy Cell is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
+ * details.
  *
- * You should have received a copy of the GNU General Public License
- * along with Privacy Cell.  If not, see <http://www.gnu.org/licenses/>.
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <https://www.gnu.org/licenses/>.
  */
 
+// The suppression of deprecation lint can be removed once the minimum API >= 31.
+@file:Suppress("DEPRECATION")
+
 package com.stoutner.privacycell.activities
 
 import android.Manifest
+import android.annotation.SuppressLint
+import android.app.ActivityManager
 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.telephony.PhoneStateListener
+import android.telephony.PhoneStateListener  // This can be replaced by `TelephonyCallback` once the minimum API >= 31.
 import android.telephony.ServiceState
+import android.telephony.SubscriptionManager
 import android.telephony.TelephonyDisplayInfo
 import android.telephony.TelephonyManager
 import android.view.MenuItem
@@ -40,7 +46,9 @@ import androidx.appcompat.app.ActionBarDrawerToggle
 import androidx.appcompat.app.AppCompatActivity
 import androidx.appcompat.content.res.AppCompatResources
 import androidx.appcompat.widget.Toolbar
+import androidx.cardview.widget.CardView
 import androidx.core.app.ActivityCompat
+import androidx.core.net.toUri
 import androidx.core.view.GravityCompat
 import androidx.drawerlayout.widget.DrawerLayout
 import androidx.preference.PreferenceManager
@@ -49,28 +57,31 @@ import com.google.android.material.navigation.NavigationView
 
 import com.stoutner.privacycell.R
 import com.stoutner.privacycell.dialogs.PhonePermissionDialog
+import com.stoutner.privacycell.dialogs.PhonePermissionDialog.StoragePermissionDialogListener
 import com.stoutner.privacycell.dialogs.WebViewDialog
+import com.stoutner.privacycell.helpers.ProtocolHelper
+import com.stoutner.privacycell.services.RealtimeMonitoringService
+
+class PrivacyCellActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelectedListener, StoragePermissionDialogListener {
+    // Define the class variables.
+    private var voiceNetworkSecurityStatus = ProtocolHelper.UNPOPULATED
+    private var dataNetworkSecurityStatus = ProtocolHelper.UNPOPULATED
 
-class PrivacyCellActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelectedListener, PhonePermissionDialog.StoragePermissionDialogListener {
     // Declare the class variables.
-    private lateinit var context: Context
-    private lateinit var telephonyManager: TelephonyManager
-    private lateinit var actionBarDrawerToggle: ActionBarDrawerToggle
+    private lateinit var phoneStateListener: PhoneStateListener  // The `PhoneStateListener` can be replaced by `TelephonyCallback` once the minimum API >= 31.
 
-    // Declare the views.
+    // Declare the class views.
+    private lateinit var actionBarDrawerToggle: ActionBarDrawerToggle
     private lateinit var drawerLayout: DrawerLayout
-    private lateinit var stingrayLinearLayout: LinearLayout
-    private lateinit var stingrayImageView: ImageView
-    private lateinit var stingrayTextView: TextView
-    private lateinit var voiceNetworkLinearLayout: LinearLayout
-    private lateinit var voiceNetworkTextView: TextView
-    private lateinit var voiceNetworkDetailsTextView: TextView
-    private lateinit var dataNetworkLinearLayout: LinearLayout
-    private lateinit var dataNetworkTextView: TextView
-    private lateinit var dataNetworkDetailsTextView: TextView
-    private lateinit var additionalNetworkInfoLinearLayout: LinearLayout
-    private lateinit var additionalNetworkInfoTextView: TextView
-    private lateinit var additionalNetworkInfoDetailsTextView: TextView
+    private lateinit var overallStatusCardView: CardView
+    private lateinit var overallStatusImageView: ImageView
+    private lateinit var overallStatusTextView: TextView
+
+    companion object {
+        // Define the public constants.
+        const val PHONE_PERMISSION_REQUEST_CODE = 0
+        const val NOTIFICATION_PERMISSION_REQUEST_CODE = 1
+    }
 
     override fun onCreate(savedInstanceState: Bundle?) {
         // Run the default commands.
@@ -79,7 +90,9 @@ class PrivacyCellActivity : AppCompatActivity(), NavigationView.OnNavigationItem
         // Get a handle for the shared preferences.
         val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this)
 
-        // Get the bottom app bar preference.
+        // Get the preferences.
+        val realtimeMonitoring = sharedPreferences.getBoolean(getString(R.string.realtime_monitoring_key), false)
+        val consider3gAntiquated = sharedPreferences.getBoolean(getString(R.string.consider_3g_antiquated_key), false)
         val bottomAppBar = sharedPreferences.getBoolean(getString(R.string.bottom_app_bar_key), false)
 
         // Set the content view.
@@ -92,24 +105,22 @@ class PrivacyCellActivity : AppCompatActivity(), NavigationView.OnNavigationItem
         // Get handles for the views.
         drawerLayout = findViewById(R.id.drawerlayout)
         val toolbar = findViewById<Toolbar>(R.id.toolbar)
-        stingrayLinearLayout = findViewById(R.id.stingray_linearlayout)
-        stingrayImageView = findViewById(R.id.stingray_imageview)
-        stingrayTextView = findViewById(R.id.stingray_textview)
-        voiceNetworkLinearLayout = findViewById(R.id.voice_network_linearlayout)
-        voiceNetworkTextView = findViewById(R.id.voice_network)
-        voiceNetworkDetailsTextView = findViewById(R.id.voice_network_details)
-        dataNetworkLinearLayout = findViewById(R.id.data_network_linearlayout)
-        dataNetworkTextView = findViewById(R.id.data_network)
-        dataNetworkDetailsTextView = findViewById(R.id.data_network_details)
-        additionalNetworkInfoLinearLayout = findViewById(R.id.additional_network_info_linearlayout)
-        additionalNetworkInfoTextView = findViewById(R.id.additional_network_info)
-        additionalNetworkInfoDetailsTextView = findViewById(R.id.additional_network_info_details)
+        overallStatusCardView = findViewById(R.id.overall_status_cardview)
+        overallStatusImageView = findViewById(R.id.overall_status_imageview)
+        overallStatusTextView = findViewById(R.id.overall_status_textview)
+        val voiceNetworkCardView = findViewById<CardView>(R.id.voice_network_cardview)
+        val voiceNetworkTextView = findViewById<TextView>(R.id.voice_network)
+        val voiceNetworkDetailsTextView = findViewById<TextView>(R.id.voice_network_details)
+        val voiceNetworkSubscriptionInfoTextView = findViewById<TextView>(R.id.voice_network_subscription_info)
+        val dataNetworkLinearLayout = findViewById<LinearLayout>(R.id.data_network_linearlayout)
+        val dataNetworkTextView = findViewById<TextView>(R.id.data_network)
+        val dataNetworkDetailsTextView = findViewById<TextView>(R.id.data_network_details)
+        val dataNetworkSubscriptionInfoTextView = findViewById<TextView>(R.id.data_network_subscription_info)
+        val additionalNetworkInfoLinearLayout = findViewById<LinearLayout>(R.id.additional_network_info_linearlayout)
+        val additionalNetworkInfoTextView = findViewById<TextView>(R.id.additional_network_info)
+        val additionalNetworkInfoDetailsTextView = findViewById<TextView>(R.id.additional_network_info_details)
         val navigationView = findViewById<NavigationView>(R.id.navigationview)
 
-        // Get handles for the context and the telephony manager.
-        context = this
-        telephonyManager = getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
-
         // Set the support action bar.
         setSupportActionBar(toolbar)
 
@@ -147,6 +158,213 @@ class PrivacyCellActivity : AppCompatActivity(), NavigationView.OnNavigationItem
                 // Do nothing.
             }
         })
+
+        // Instantiate the protocol helper.
+        val protocolHelper = ProtocolHelper()
+
+        // Get a handle for the subscription manager.
+        val subscriptionManager = getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE) as SubscriptionManager
+
+        // Define the phone state listener.  The `PhoneStateListener` can be replaced by `TelephonyCallback` once the minimum API >= 31.
+        phoneStateListener = object : PhoneStateListener() {
+            @Deprecated("Deprecated in Java")
+            override fun onServiceStateChanged(serviceState: ServiceState) {  // Update the voice network.
+                // Get the network registration info for the voice network, which is the second of the three entries (the first appears to be Wi-Fi and the third appears to be the cell data network).
+                val networkRegistrationInfo = serviceState.networkRegistrationInfoList[1]
+
+                // Get the voice network type int.
+                val voiceNetworkTypeInt = networkRegistrationInfo.accessNetworkTechnology
+
+                // Get the voice network security status.
+                voiceNetworkSecurityStatus = protocolHelper.checkNetwork(voiceNetworkTypeInt, consider3gAntiquated)
+
+                // Get the voice network type.
+                val voiceNetworkStringArray = protocolHelper.getNetworkTypeStringArray(voiceNetworkTypeInt, applicationContext)
+
+                // Get the default voice subscription id.
+                val voiceSubscriptionId = SubscriptionManager.getDefaultVoiceSubscriptionId()
+
+                // Create the voice subscription info string.
+                var voiceSubscriptionInfoString = ""
+
+                // Populate the voice carrier info string if the appropriate permission has been granted.
+                if (ActivityCompat.checkSelfPermission(applicationContext, Manifest.permission.READ_PHONE_NUMBERS) == PackageManager.PERMISSION_GRANTED) {
+                    // Populate the voice carrier info string.  The deprecated command must be used until the API >= 33.
+                    voiceSubscriptionInfoString = if (Build.VERSION.SDK_INT <= 32)
+                        "${subscriptionManager.getActiveSubscriptionInfo(voiceSubscriptionId).carrierName} – ${subscriptionManager.getActiveSubscriptionInfo(voiceSubscriptionId).number}"
+                    else
+                        "${subscriptionManager.getActiveSubscriptionInfo(voiceSubscriptionId).carrierName} – ${subscriptionManager.getPhoneNumber(voiceSubscriptionId)}"
+                }
+
+                // Populate the voice network text views.
+                voiceNetworkTextView.text = getString(R.string.voice_network, voiceNetworkStringArray[0])
+                voiceNetworkDetailsTextView.text = voiceNetworkStringArray[1]
+                voiceNetworkSubscriptionInfoTextView.text = voiceSubscriptionInfoString
+
+                // Hide the voice network details text view if it is empty, which happens with Wi-Fi calling.
+                if (voiceNetworkDetailsTextView.text.isNullOrBlank())
+                    voiceNetworkDetailsTextView.visibility = View.GONE
+                else
+                    voiceNetworkDetailsTextView.visibility = View.VISIBLE
+
+                // Set the color of the voice network.
+                when (voiceNetworkSecurityStatus) {
+                    ProtocolHelper.SECURE -> voiceNetworkTextView.setTextColor(getColor(R.color.blue_text))
+                    ProtocolHelper.INSECURE -> voiceNetworkTextView.setTextColor(getColor(R.color.yellow_text))
+                    ProtocolHelper.ANTIQUATED -> voiceNetworkTextView.setTextColor(getColor(R.color.red_text))
+                }
+
+                // Set the voice network click listener.
+                voiceNetworkCardView.setOnClickListener {
+                    // Instantiate the voice network dialog fragment according to the network type.
+                    val voiceNetworkDialogFragment = when (voiceNetworkTypeInt) {
+                        TelephonyManager.NETWORK_TYPE_UNKNOWN -> WebViewDialog().type(WebViewDialog.NETWORK_UNKNOWN)
+                        TelephonyManager.NETWORK_TYPE_GPRS -> WebViewDialog().type(WebViewDialog.NETWORK_GPRS)
+                        TelephonyManager.NETWORK_TYPE_EDGE -> WebViewDialog().type(WebViewDialog.NETWORK_EDGE)
+                        TelephonyManager.NETWORK_TYPE_UMTS -> WebViewDialog().type(WebViewDialog.NETWORK_UMTS)
+                        TelephonyManager.NETWORK_TYPE_CDMA -> WebViewDialog().type(WebViewDialog.NETWORK_CDMA)
+                        TelephonyManager.NETWORK_TYPE_EVDO_0 -> WebViewDialog().type(WebViewDialog.NETWORK_EVDO_0)
+                        TelephonyManager.NETWORK_TYPE_EVDO_A -> WebViewDialog().type(WebViewDialog.NETWORK_EVDO_A)
+                        TelephonyManager.NETWORK_TYPE_1xRTT -> WebViewDialog().type(WebViewDialog.NETWORK_1XRTT)
+                        TelephonyManager.NETWORK_TYPE_HSDPA -> WebViewDialog().type(WebViewDialog.NETWORK_HSDPA)
+                        TelephonyManager.NETWORK_TYPE_HSUPA -> WebViewDialog().type(WebViewDialog.NETWORK_HSUPA)
+                        TelephonyManager.NETWORK_TYPE_HSPA -> WebViewDialog().type(WebViewDialog.NETWORK_HSPA)
+                        TelephonyManager.NETWORK_TYPE_IDEN -> WebViewDialog().type(WebViewDialog.NETWORK_IDEN)
+                        TelephonyManager.NETWORK_TYPE_EVDO_B -> WebViewDialog().type(WebViewDialog.NETWORK_EVDO_B)
+                        TelephonyManager.NETWORK_TYPE_LTE -> WebViewDialog().type(WebViewDialog.NETWORK_LTE)
+                        TelephonyManager.NETWORK_TYPE_EHRPD -> WebViewDialog().type(WebViewDialog.NETWORK_EHRPD)
+                        TelephonyManager.NETWORK_TYPE_HSPAP -> WebViewDialog().type(WebViewDialog.NETWORK_HSPAP)
+                        TelephonyManager.NETWORK_TYPE_GSM -> WebViewDialog().type(WebViewDialog.NETWORK_GSM)
+                        TelephonyManager.NETWORK_TYPE_TD_SCDMA -> WebViewDialog().type(WebViewDialog.NETWORK_TD_SCDMA)
+                        TelephonyManager.NETWORK_TYPE_IWLAN -> WebViewDialog().type(WebViewDialog.NETWORK_IWLAN)
+                        TelephonyManager.NETWORK_TYPE_NR -> WebViewDialog().type(WebViewDialog.NETWORK_NR)
+                        else -> WebViewDialog().type(WebViewDialog.NETWORK_UNKNOWN)
+                    }
+
+                    // Show the alert dialog.
+                    voiceNetworkDialogFragment.show(supportFragmentManager, getString(R.string.voice_network))
+                }
+
+                // Populate the overall security status.
+                populateOverallSecurityStatus()
+            }
+
+            @Deprecated("Deprecated in Java")
+            @SuppressLint("SwitchIntDef")
+            override fun onDisplayInfoChanged(telephonyDisplayInfo: TelephonyDisplayInfo) {  // Update the data network.
+                // Get the network type integers.  <https://source.android.com/devices/tech/connect/acts-5g-testing>
+                val dataNetworkTypeInt = telephonyDisplayInfo.networkType
+                val additionalNetworkInfoTypeInt = telephonyDisplayInfo.overrideNetworkType
+
+                // Get the data network security status.
+                dataNetworkSecurityStatus = protocolHelper.checkNetwork(dataNetworkTypeInt, consider3gAntiquated)
+
+                // Get the strings that correspond to the network information.
+                val dataNetworkStringArray = protocolHelper.getNetworkTypeStringArray(dataNetworkTypeInt, applicationContext)
+                val additionalNetworkInfoStringArray = protocolHelper.getAdditionalNetworkInfoStringArray(additionalNetworkInfoTypeInt, applicationContext)
+
+                // Get the active data subscription id.
+                val dataSubscriptionId = SubscriptionManager.getActiveDataSubscriptionId()
+
+                // Create the data carrier info string.
+                var dataSubscriptionInfoString = ""
+
+                // Populate the data carrier info string if the appropriate permission has been granted.
+                if (ActivityCompat.checkSelfPermission(applicationContext, Manifest.permission.READ_PHONE_NUMBERS) == PackageManager.PERMISSION_GRANTED) {
+                    // Populate the data carrier info string.  The deprecated command must be used until the API >= 33.
+                    dataSubscriptionInfoString = if (Build.VERSION.SDK_INT <= 32)
+                        "${subscriptionManager.getActiveSubscriptionInfo(dataSubscriptionId).carrierName} – ${subscriptionManager.getActiveSubscriptionInfo(dataSubscriptionId).number}"
+                    else
+                        "${subscriptionManager.getActiveSubscriptionInfo(dataSubscriptionId).carrierName} – ${subscriptionManager.getPhoneNumber(dataSubscriptionId)}"
+                }
+
+                // Populate the data network text views.
+                dataNetworkTextView.text = getString(R.string.data_network, dataNetworkStringArray[0])
+                dataNetworkDetailsTextView.text = dataNetworkStringArray[1]
+                dataNetworkSubscriptionInfoTextView.text = dataSubscriptionInfoString
+                additionalNetworkInfoTextView.text = getString(R.string.additional_network_info, additionalNetworkInfoStringArray[0])
+                additionalNetworkInfoDetailsTextView.text = additionalNetworkInfoStringArray[1]
+
+                // Set the color of the data network.
+                when (dataNetworkSecurityStatus) {
+                    ProtocolHelper.SECURE -> dataNetworkTextView.setTextColor(getColor(R.color.blue_text))
+                    ProtocolHelper.INSECURE -> dataNetworkTextView.setTextColor(getColor(R.color.yellow_text))
+                    ProtocolHelper.ANTIQUATED -> dataNetworkTextView.setTextColor(getColor(R.color.red_text))
+                }
+
+                // Set the color of the additional network info.
+                when (protocolHelper.checkAdditionalNetworkInfo(additionalNetworkInfoTypeInt)) {
+                    ProtocolHelper.SECURE -> additionalNetworkInfoTextView.setTextColor(getColor(R.color.blue_text))
+                    ProtocolHelper.INSECURE -> additionalNetworkInfoTextView.setTextColor(getColor(R.color.yellow_text))
+                    ProtocolHelper.ANTIQUATED -> additionalNetworkInfoTextView.setTextColor(getColor(R.color.red_text))
+                }
+
+                // Set the data network click listener.
+                dataNetworkLinearLayout.setOnClickListener {
+                    // Instantiate the data network dialog fragment according to the network type.
+                    val dataNetworkDialogFragment = when (dataNetworkTypeInt) {
+                        TelephonyManager.NETWORK_TYPE_UNKNOWN -> WebViewDialog().type(WebViewDialog.NETWORK_UNKNOWN)
+                        TelephonyManager.NETWORK_TYPE_GPRS -> WebViewDialog().type(WebViewDialog.NETWORK_GPRS)
+                        TelephonyManager.NETWORK_TYPE_EDGE -> WebViewDialog().type(WebViewDialog.NETWORK_EDGE)
+                        TelephonyManager.NETWORK_TYPE_UMTS -> WebViewDialog().type(WebViewDialog.NETWORK_UMTS)
+                        TelephonyManager.NETWORK_TYPE_CDMA -> WebViewDialog().type(WebViewDialog.NETWORK_CDMA)
+                        TelephonyManager.NETWORK_TYPE_EVDO_0 -> WebViewDialog().type(WebViewDialog.NETWORK_EVDO_0)
+                        TelephonyManager.NETWORK_TYPE_EVDO_A -> WebViewDialog().type(WebViewDialog.NETWORK_EVDO_A)
+                        TelephonyManager.NETWORK_TYPE_1xRTT -> WebViewDialog().type(WebViewDialog.NETWORK_1XRTT)
+                        TelephonyManager.NETWORK_TYPE_HSDPA -> WebViewDialog().type(WebViewDialog.NETWORK_HSDPA)
+                        TelephonyManager.NETWORK_TYPE_HSUPA -> WebViewDialog().type(WebViewDialog.NETWORK_HSUPA)
+                        TelephonyManager.NETWORK_TYPE_HSPA -> WebViewDialog().type(WebViewDialog.NETWORK_HSPA)
+                        TelephonyManager.NETWORK_TYPE_IDEN -> WebViewDialog().type(WebViewDialog.NETWORK_IDEN)
+                        TelephonyManager.NETWORK_TYPE_EVDO_B -> WebViewDialog().type(WebViewDialog.NETWORK_EVDO_B)
+                        TelephonyManager.NETWORK_TYPE_LTE -> WebViewDialog().type(WebViewDialog.NETWORK_LTE)
+                        TelephonyManager.NETWORK_TYPE_EHRPD -> WebViewDialog().type(WebViewDialog.NETWORK_EHRPD)
+                        TelephonyManager.NETWORK_TYPE_HSPAP -> WebViewDialog().type(WebViewDialog.NETWORK_HSPAP)
+                        TelephonyManager.NETWORK_TYPE_GSM -> WebViewDialog().type(WebViewDialog.NETWORK_GSM)
+                        TelephonyManager.NETWORK_TYPE_TD_SCDMA -> WebViewDialog().type(WebViewDialog.NETWORK_TD_SCDMA)
+                        TelephonyManager.NETWORK_TYPE_IWLAN -> WebViewDialog().type(WebViewDialog.NETWORK_IWLAN)
+                        TelephonyManager.NETWORK_TYPE_NR -> WebViewDialog().type(WebViewDialog.NETWORK_NR)
+                        else -> WebViewDialog().type(WebViewDialog.NETWORK_UNKNOWN)
+                    }
+
+                    // Show the alert dialog.
+                    dataNetworkDialogFragment.show(supportFragmentManager, getString(R.string.voice_network))
+                }
+
+                // Set the additional network info click listener.
+                additionalNetworkInfoLinearLayout.setOnClickListener {
+                    // Instantiate the initial network info dialog fragment according to the network type.
+                    val additionalNetworkInfoDialogFragment = when (telephonyDisplayInfo.overrideNetworkType) {
+                        TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE -> WebViewDialog().type(WebViewDialog.OVERRIDE_NETWORK_NONE)
+                        TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_CA -> WebViewDialog().type(WebViewDialog.OVERRIDE_NETWORK_LTE_CA)
+                        TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_ADVANCED_PRO -> WebViewDialog().type(WebViewDialog.OVERRIDE_NETWORK_LTE_ADVANCED_PRO)
+                        TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA -> WebViewDialog().type(WebViewDialog.OVERRIDE_NETWORK_NR_NSA)
+                        TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA_MMWAVE -> WebViewDialog().type(WebViewDialog.OVERRIDE_NETWORK_NR_NSA_MMWAVE)  // Can be removed once the minimum API >= 31.
+                        TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED -> WebViewDialog().type(WebViewDialog.OVERRIDE_NETWORK_NR_ADVANCED)
+                        else -> WebViewDialog().type(WebViewDialog.OVERRIDE_NETWORK_NONE)
+                    }
+
+                    // Show the alert dialog.
+                    additionalNetworkInfoDialogFragment.show(supportFragmentManager, getString(R.string.voice_network))
+                }
+
+                // Populate the overall security status.
+                populateOverallSecurityStatus()
+            }
+        }
+
+        // Start the realtime monitoring service if it is enabled.
+        if (realtimeMonitoring) {
+            // Get a handle for the activity manager.
+            val activityManager: ActivityManager = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
+
+            // Get a list of the running service info.  The deprecated `getRunningServices()` now only returns services stared by Privacy Cell, but that is all we want to know anyway.
+            val runningServiceInfoList: List<ActivityManager.RunningServiceInfo> = activityManager.getRunningServices(1)
+
+            // Start the service if it is not already running.
+            if (runningServiceInfoList.isEmpty()) {
+                startService(Intent(this, RealtimeMonitoringService::class.java))
+            }
+        }
     }
 
     override fun onPostCreate(savedInstanceState: Bundle?) {
@@ -157,18 +375,19 @@ class PrivacyCellActivity : AppCompatActivity(), NavigationView.OnNavigationItem
         actionBarDrawerToggle.syncState()
     }
 
-    override fun onResume() {
+    override fun onStart() {
         // Run the default commands.
-        super.onResume()
+        super.onStart()
 
-        // Check to see if the read phone state permission has been granted.  These commands need to be run on every resume so that the listener gets reassigned as it is automatically paused.
-        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED) {  // The storage permission has been granted.
-            // Populate Privacy Cell.
-            populatePrivacyCell()
+        // Check to see if the read phone state permission has been granted.  These commands need to be run on every start so that the listener is reregistered.
+        if ((ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED) &&
+            (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_NUMBERS) == PackageManager.PERMISSION_GRANTED)) {  // The phone permissions have been granted.
+            // Register the telephony manager listener.
+            registerTelephonyManagerListener()
         } else {  // The phone permission has not been granted.
             // Check if the user has previously denied the storage permission.
             if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.READ_PHONE_STATE)) {  // Show a dialog explaining the request first.
-                // Check to see if a phone permission dialog is already displayed.  This happens if the app is restarted when the dialog is shown.
+                // Check to see if a phone permission dialog is already displayed.  This happens if the app is restarted while the dialog is shown.
                 if (supportFragmentManager.findFragmentByTag(getString(R.string.phone_permission)) == null) {  // No dialog is currently shown.
                     // Instantiate the phone permission dialog fragment.
                     val phonePermissionDialogFragment = PhonePermissionDialog()
@@ -177,12 +396,23 @@ class PrivacyCellActivity : AppCompatActivity(), NavigationView.OnNavigationItem
                     phonePermissionDialogFragment.show(supportFragmentManager, getString(R.string.phone_permission))
                 }
             } else {  // Show the permission request directly.
-                // Request the read phone state permission.  There is only one permission request in the app, so it has a request code of 0.
-                ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.READ_PHONE_STATE), 0)
+                // Request the read phone state permission.
+                ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.READ_PHONE_STATE, Manifest.permission.READ_PHONE_NUMBERS), PHONE_PERMISSION_REQUEST_CODE)
             }
         }
     }
 
+    override fun onStop() {
+        // Run the default commands.
+        super.onStop()
+
+        // Get a handle for the telephony manager.
+        val telephonyManager = getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
+
+        // Unregister the telephony manager listener.  The `PhoneStateListener` can be replaced by `TelephonyCallback` once the minimum API >= 31.
+        telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_NONE)
+    }
+
     override fun onNavigationItemSelected(menuItem: MenuItem) : Boolean {
         // Run the commands that correspond to the selected menu item.
         when (menuItem.itemId) {
@@ -194,6 +424,22 @@ class PrivacyCellActivity : AppCompatActivity(), NavigationView.OnNavigationItem
                 startActivity(settingsIntent)
             }
 
+            R.id.protocols -> {
+                // Create an intent to load the Protocols activity.
+                val protocolsIntent = Intent(this, ProtocolsActivity::class.java)
+
+                // Make it so.
+                startActivity(protocolsIntent)
+            }
+
+            R.id.logcat -> {  // Logcat.
+                // Create an intent to load the Logcat activity.
+                val logcatIntent = Intent(this, LogcatActivity::class.java)
+
+                // Make it so.
+                startActivity(logcatIntent)
+            }
+
             R.id.permissions -> {  // Permissions.
                 // Instantiate the permissions dialog fragment.
                 val permissionsDialogFragment = WebViewDialog().type(WebViewDialog.PERMISSIONS)
@@ -239,7 +485,7 @@ class PrivacyCellActivity : AppCompatActivity(), NavigationView.OnNavigationItem
                 val newsUrlIntent = Intent(Intent.ACTION_VIEW)
 
                 // Add the URL to the intent.
-                newsUrlIntent.data = Uri.parse("https://www.stoutner.com/category/privacy-cell/")
+                newsUrlIntent.data = "https://www.stoutner.com/category/privacy-cell/".toUri()
 
                 // Make it so.
                 startActivity(newsUrlIntent)
@@ -250,7 +496,7 @@ class PrivacyCellActivity : AppCompatActivity(), NavigationView.OnNavigationItem
                 val roadmapUrlIntent = Intent(Intent.ACTION_VIEW)
 
                 // Add the URL to the intent.
-                roadmapUrlIntent.data = Uri.parse("https://www.stoutner.com/category/privacy-cell-roadmap/")
+                roadmapUrlIntent.data = "https://www.stoutner.com/category/privacy-cell-roadmap/".toUri()
 
                 // Make it so.
                 startActivity(roadmapUrlIntent)
@@ -261,7 +507,7 @@ class PrivacyCellActivity : AppCompatActivity(), NavigationView.OnNavigationItem
                 val bugTrackerUrlIntent = Intent(Intent.ACTION_VIEW)
 
                 // Add the URL to the intent.
-                bugTrackerUrlIntent.data = Uri.parse("https://redmine.stoutner.com/projects/privacy-cell/issues")
+                bugTrackerUrlIntent.data = "https://redmine.stoutner.com/projects/privacy-cell/issues".toUri()
 
                 // Make it so.
                 startActivity(bugTrackerUrlIntent)
@@ -272,7 +518,7 @@ class PrivacyCellActivity : AppCompatActivity(), NavigationView.OnNavigationItem
                 val forumUrlIntent = Intent(Intent.ACTION_VIEW)
 
                 // Add the URL to the intent.
-                forumUrlIntent.data = Uri.parse("https://redmine.stoutner.com/projects/privacy-cell/boards")
+                forumUrlIntent.data = "https://redmine.stoutner.com/projects/privacy-cell/boards".toUri()
 
                 // Make it so.
                 startActivity(forumUrlIntent)
@@ -283,7 +529,7 @@ class PrivacyCellActivity : AppCompatActivity(), NavigationView.OnNavigationItem
                 val donationsUrlIntent = Intent(Intent.ACTION_VIEW)
 
                 // Add the URL to the intent.
-                donationsUrlIntent.data = Uri.parse("https://www.stoutner.com/donations/")
+                donationsUrlIntent.data = "https://www.stoutner.com/donations/".toUri()
 
                 // Make it so.
                 startActivity(donationsUrlIntent)
@@ -298,200 +544,85 @@ class PrivacyCellActivity : AppCompatActivity(), NavigationView.OnNavigationItem
     }
 
     override fun onCloseStoragePermissionDialog() {
-        // Request the read phone state permission.  There is only one permission request in the app, so it has a request code of 0.
-        ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.READ_PHONE_STATE), 0)
+        // Request the read phone state permission.
+        ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.READ_PHONE_STATE), PHONE_PERMISSION_REQUEST_CODE)
     }
 
     override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
         // Run the default commands.
         super.onRequestPermissionsResult(requestCode, permissions, grantResults)
 
-        //Only process the results if they exist (this method is triggered when a dialog is presented the first time for an app, but no grant results are included).
-        if (grantResults.isNotEmpty()) {
+        // Only process the results if they exist (this method is triggered when a dialog is presented the first time for an app, but no grant results are included) and the result is for the phone permission.
+        if (grantResults.isNotEmpty() && (requestCode == PHONE_PERMISSION_REQUEST_CODE)) {
             // Check to see if the read phone state permission was granted.  If the dialog was canceled the grant results will be empty.
             if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {  // The read phone state permission was granted.
                 // Populate Privacy Cell.
-                populatePrivacyCell()
+                registerTelephonyManagerListener()
             } else {  // The read phone state permission was denied.
                 // Display the phone permission text on the main activity.
-                stingrayTextView.text = getString(R.string.phone_permission_text)
+               overallStatusTextView.text = getString(R.string.phone_permission_text)
             }
         }
     }
 
-    private fun populatePrivacyCell() {
-        // Listen to changes in the cell network state.
-        telephonyManager.listen(object : PhoneStateListener() {
-            override fun onDisplayInfoChanged(telephonyDisplayInfo: TelephonyDisplayInfo) {
-                // Populate the stingray security information.  <https://source.android.com/devices/tech/connect/acts-5g-testing>
-                if (telephonyDisplayInfo.networkType == TelephonyManager.NETWORK_TYPE_NR) {  // This is a secure 5G NR SA network.
-                    // Populate the image view.
-                    stingrayImageView.setImageDrawable(AppCompatResources.getDrawable(context, R.drawable.secure_5g_nr_sa))
-
-                    // Set the text.
-                    stingrayTextView.text = getString(R.string.secure_from_stingray)
-
-                    // Set the text color.
-                    stingrayTextView.setTextColor(getColor(R.color.blue_text))
-                } else {  // This is not a secure 5G NR SA network.
-                    // Populate the image view.
-                    stingrayImageView.setImageDrawable(AppCompatResources.getDrawable(context, R.drawable.not_secure))
-
-                    // Set the text.
-                    stingrayTextView.text = getString(R.string.not_secure_from_stingray)
-
-                    // Set the text color.
-                    stingrayTextView.setTextColor(getColor(R.color.red_text))
-                }
-
-                // Get the strings that correspond to the network information.
-                val dataNetworkType = getNetworkType(telephonyDisplayInfo.networkType)
-                val additionalNetworkInfo = getAdditionalNetworkInfo(telephonyDisplayInfo.overrideNetworkType)
-
-                // Populate the data network text views.
-                dataNetworkTextView.text = getString(R.string.data_network, dataNetworkType[0])
-                dataNetworkDetailsTextView.text = dataNetworkType[1]
-                additionalNetworkInfoTextView.text = getString(R.string.additional_network_info, additionalNetworkInfo[0])
-                additionalNetworkInfoDetailsTextView.text = additionalNetworkInfo[1]
+    private fun registerTelephonyManagerListener() {
+        // Get a handle for the telephony manager.
+        val telephonyManager = getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
 
-                // Set the stingray click listener.
-                stingrayLinearLayout.setOnClickListener {
-                    // Instantiate the stingray dialog fragment.
-                    val stingrayDialogFragment = WebViewDialog().type(WebViewDialog.STINGRAY)
+        // Listen to changes in the cell network state.  The `PhoneStateListener` can be replaced by `TelephonyCallback` once the minimum API >= 31.
+        telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_SERVICE_STATE or PhoneStateListener.LISTEN_DISPLAY_INFO_CHANGED)
+    }
 
-                    // Show the alert dialog.
-                    stingrayDialogFragment.show(supportFragmentManager, getString(R.string.stingrays))
-                }
+    private fun populateOverallSecurityStatus() {
+        // Create an overall status dialog type integer.
+        val overallStatusDialogTypeInt: Int
 
-                // Set the data network click listener.
-                dataNetworkLinearLayout.setOnClickListener {
-                    // Instantiate the data network dialog fragment according to the network type.
-                    val dataNetworkDialogFragment = when (telephonyDisplayInfo.networkType) {
-                        TelephonyManager.NETWORK_TYPE_UNKNOWN -> WebViewDialog().type(WebViewDialog.NETWORK_UNKNOWN)
-                        TelephonyManager.NETWORK_TYPE_GPRS -> WebViewDialog().type(WebViewDialog.NETWORK_GPRS)
-                        TelephonyManager.NETWORK_TYPE_EDGE -> WebViewDialog().type(WebViewDialog.NETWORK_EDGE)
-                        TelephonyManager.NETWORK_TYPE_UMTS -> WebViewDialog().type(WebViewDialog.NETWORK_UMTS)
-                        TelephonyManager.NETWORK_TYPE_CDMA -> WebViewDialog().type(WebViewDialog.NETWORK_CDMA)
-                        TelephonyManager.NETWORK_TYPE_EVDO_0 -> WebViewDialog().type(WebViewDialog.NETWORK_EVDO_0)
-                        TelephonyManager.NETWORK_TYPE_EVDO_A -> WebViewDialog().type(WebViewDialog.NETWORK_EVDO_A)
-                        TelephonyManager.NETWORK_TYPE_1xRTT -> WebViewDialog().type(WebViewDialog.NETWORK_1xRTT)
-                        TelephonyManager.NETWORK_TYPE_HSDPA -> WebViewDialog().type(WebViewDialog.NETWORK_HSDPA)
-                        TelephonyManager.NETWORK_TYPE_HSUPA -> WebViewDialog().type(WebViewDialog.NETWORK_HSUPA)
-                        TelephonyManager.NETWORK_TYPE_HSPA -> WebViewDialog().type(WebViewDialog.NETWORK_HSPA)
-                        TelephonyManager.NETWORK_TYPE_IDEN -> WebViewDialog().type(WebViewDialog.NETWORK_IDEN)
-                        TelephonyManager.NETWORK_TYPE_EVDO_B -> WebViewDialog().type(WebViewDialog.NETWORK_EVDO_B)
-                        TelephonyManager.NETWORK_TYPE_LTE -> WebViewDialog().type(WebViewDialog.NETWORK_LTE)
-                        TelephonyManager.NETWORK_TYPE_EHRPD -> WebViewDialog().type(WebViewDialog.NETWORK_EHRPD)
-                        TelephonyManager.NETWORK_TYPE_HSPAP -> WebViewDialog().type(WebViewDialog.NETWORK_HSPAP)
-                        TelephonyManager.NETWORK_TYPE_GSM -> WebViewDialog().type(WebViewDialog.NETWORK_GSM)
-                        TelephonyManager.NETWORK_TYPE_TD_SCDMA -> WebViewDialog().type(WebViewDialog.NETWORK_TD_SCDMA)
-                        TelephonyManager.NETWORK_TYPE_IWLAN -> WebViewDialog().type(WebViewDialog.NETWORK_IWLAN)
-                        TelephonyManager.NETWORK_TYPE_NR -> WebViewDialog().type(WebViewDialog.NETWORK_NR)
-                        else -> WebViewDialog().type(WebViewDialog.NETWORK_UNKNOWN)
-                    }
+        // Populate the over security status.
+        if ((voiceNetworkSecurityStatus == ProtocolHelper.ANTIQUATED) || (dataNetworkSecurityStatus == ProtocolHelper.ANTIQUATED)) {  // This is an antiquated network.
+            // Populate the image view.
+            overallStatusImageView.setImageDrawable(AppCompatResources.getDrawable(applicationContext, R.drawable.antiquated))
 
-                    // Show the alert dialog.
-                    dataNetworkDialogFragment.show(supportFragmentManager, getString(R.string.voice_network))
-                }
+            // Set the text.
+            overallStatusTextView.text = getString(R.string.antiquated_protocols)
 
-                // Set the additional network info click listener.
-                additionalNetworkInfoLinearLayout.setOnClickListener {
-                    // Instantiate the initial network info dialog fragment according to the network type.
-                    val additionalNetworkInfoDialogFragment = when (telephonyDisplayInfo.overrideNetworkType) {
-                        TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE -> WebViewDialog().type(WebViewDialog.OVERRIDE_NETWORK_NONE)
-                        TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_CA -> WebViewDialog().type(WebViewDialog.OVERRIDE_NETWORK_LTE_CA)
-                        TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_ADVANCED_PRO -> WebViewDialog().type(WebViewDialog.OVERRIDE_NETWORK_LTE_ADVANCED_PRO)
-                        TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA -> WebViewDialog().type(WebViewDialog.OVERRIDE_NETWORK_NR_NSA)
-                        TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA_MMWAVE -> WebViewDialog().type(WebViewDialog.OVERRIDE_NETWORK_NR_NSA_MMWAVE)
-                        else -> WebViewDialog().type(WebViewDialog.OVERRIDE_NETWORK_NR_NSA_MMWAVE)
-                    }
+            // Set the text color.
+            overallStatusTextView.setTextColor(getColor(R.color.red_text))
 
-                    // Show the alert dialog.
-                    additionalNetworkInfoDialogFragment.show(supportFragmentManager, getString(R.string.voice_network))
-                }
-            }
+            // Set the stingray dialog type integer.
+            overallStatusDialogTypeInt = WebViewDialog.ANTIQUATED_NETWORK
+        } else if ((voiceNetworkSecurityStatus == ProtocolHelper.INSECURE) || (dataNetworkSecurityStatus == ProtocolHelper.INSECURE)) {  // This is an insecure network.
+            // Populate the image view.
+            overallStatusImageView.setImageDrawable(AppCompatResources.getDrawable(applicationContext, R.drawable.insecure))
 
-            override fun onServiceStateChanged(serviceState: ServiceState) {
-                // Get the network registration info for the voice network, which is the second of the three entries (the first appears to be Wi-Fi and the third appears to be the cell data network).
-                val networkRegistrationInfo = serviceState.networkRegistrationInfoList[1]
+            // Set the text.
+            overallStatusTextView.text = getString(R.string.insecure_protocols)
 
-                // Get the voice network type.
-                val voiceNetworkType = getNetworkType(networkRegistrationInfo.accessNetworkTechnology)
+            // Set the text color.
+            overallStatusTextView.setTextColor(getColor(R.color.yellow_text))
 
-                // Populate the voice network text views.
-                voiceNetworkTextView.text = getString(R.string.voice_network, voiceNetworkType[0])
-                voiceNetworkDetailsTextView.text = voiceNetworkType[1]
+            // Set the stingray dialog type integer.
+            overallStatusDialogTypeInt = WebViewDialog.STINGRAY
+        } else {  // This is a secure network.
+            // Populate the image view.
+            overallStatusImageView.setImageDrawable(AppCompatResources.getDrawable(applicationContext, R.drawable.secure))
 
-                // Set the voice network click listener.
-                voiceNetworkLinearLayout.setOnClickListener {
-                    // Instantiate the voice network dialog fragment according to the network type.
-                    val voiceNetworkDialogFragment = when (networkRegistrationInfo.accessNetworkTechnology) {
-                        TelephonyManager.NETWORK_TYPE_UNKNOWN -> WebViewDialog().type(WebViewDialog.NETWORK_UNKNOWN)
-                        TelephonyManager.NETWORK_TYPE_GPRS -> WebViewDialog().type(WebViewDialog.NETWORK_GPRS)
-                        TelephonyManager.NETWORK_TYPE_EDGE -> WebViewDialog().type(WebViewDialog.NETWORK_EDGE)
-                        TelephonyManager.NETWORK_TYPE_UMTS -> WebViewDialog().type(WebViewDialog.NETWORK_UMTS)
-                        TelephonyManager.NETWORK_TYPE_CDMA -> WebViewDialog().type(WebViewDialog.NETWORK_CDMA)
-                        TelephonyManager.NETWORK_TYPE_EVDO_0 -> WebViewDialog().type(WebViewDialog.NETWORK_EVDO_0)
-                        TelephonyManager.NETWORK_TYPE_EVDO_A -> WebViewDialog().type(WebViewDialog.NETWORK_EVDO_A)
-                        TelephonyManager.NETWORK_TYPE_1xRTT -> WebViewDialog().type(WebViewDialog.NETWORK_1xRTT)
-                        TelephonyManager.NETWORK_TYPE_HSDPA -> WebViewDialog().type(WebViewDialog.NETWORK_HSDPA)
-                        TelephonyManager.NETWORK_TYPE_HSUPA -> WebViewDialog().type(WebViewDialog.NETWORK_HSUPA)
-                        TelephonyManager.NETWORK_TYPE_HSPA -> WebViewDialog().type(WebViewDialog.NETWORK_HSPA)
-                        TelephonyManager.NETWORK_TYPE_IDEN -> WebViewDialog().type(WebViewDialog.NETWORK_IDEN)
-                        TelephonyManager.NETWORK_TYPE_EVDO_B -> WebViewDialog().type(WebViewDialog.NETWORK_EVDO_B)
-                        TelephonyManager.NETWORK_TYPE_LTE -> WebViewDialog().type(WebViewDialog.NETWORK_LTE)
-                        TelephonyManager.NETWORK_TYPE_EHRPD -> WebViewDialog().type(WebViewDialog.NETWORK_EHRPD)
-                        TelephonyManager.NETWORK_TYPE_HSPAP -> WebViewDialog().type(WebViewDialog.NETWORK_HSPAP)
-                        TelephonyManager.NETWORK_TYPE_GSM -> WebViewDialog().type(WebViewDialog.NETWORK_GSM)
-                        TelephonyManager.NETWORK_TYPE_TD_SCDMA -> WebViewDialog().type(WebViewDialog.NETWORK_TD_SCDMA)
-                        TelephonyManager.NETWORK_TYPE_IWLAN -> WebViewDialog().type(WebViewDialog.NETWORK_IWLAN)
-                        TelephonyManager.NETWORK_TYPE_NR -> WebViewDialog().type(WebViewDialog.NETWORK_NR)
-                        else -> WebViewDialog().type(WebViewDialog.NETWORK_UNKNOWN)
-                    }
+            // Set the text.
+            overallStatusTextView.text = getString(R.string.secure_protocols)
 
-                    // Show the alert dialog.
-                    voiceNetworkDialogFragment.show(supportFragmentManager, getString(R.string.voice_network))
-                }
-            }
-        }, PhoneStateListener.LISTEN_DISPLAY_INFO_CHANGED or PhoneStateListener.LISTEN_SERVICE_STATE)
-    }
+            // Set the text color.
+            overallStatusTextView.setTextColor(getColor(R.color.blue_text))
 
-    private fun getNetworkType(networkType: Int) : Array<String> {
-        // Return the string that corresponds to the network type.
-        return when(networkType) {
-            TelephonyManager.NETWORK_TYPE_UNKNOWN -> arrayOf(getString(R.string.unknown), "")
-            TelephonyManager.NETWORK_TYPE_GPRS -> arrayOf(getString(R.string.gprs), getString(R.string.gprs_detail))
-            TelephonyManager.NETWORK_TYPE_EDGE -> arrayOf(getString(R.string.edge), getString(R.string.edge_detail))
-            TelephonyManager.NETWORK_TYPE_UMTS -> arrayOf(getString(R.string.umts), getString(R.string.umts_detail))
-            TelephonyManager.NETWORK_TYPE_CDMA -> arrayOf(getString(R.string.cdma), getString(R.string.cdma_detail))
-            TelephonyManager.NETWORK_TYPE_EVDO_0 -> arrayOf(getString(R.string.evdo_0), getString(R.string.evdo_0_detail))
-            TelephonyManager.NETWORK_TYPE_EVDO_A -> arrayOf(getString(R.string.evdo_a), getString(R.string.evdo_a_detail))
-            TelephonyManager.NETWORK_TYPE_1xRTT -> arrayOf(getString(R.string.rtt), getString(R.string.rtt_detail))
-            TelephonyManager.NETWORK_TYPE_HSDPA -> arrayOf(getString(R.string.hsdpa), getString(R.string.hsdpa_detail))
-            TelephonyManager.NETWORK_TYPE_HSUPA -> arrayOf(getString(R.string.hsupa), getString(R.string.hsupa_detail))
-            TelephonyManager.NETWORK_TYPE_HSPA -> arrayOf(getString(R.string.hspa), getString(R.string.hspa_detail))
-            TelephonyManager.NETWORK_TYPE_IDEN -> arrayOf(getString(R.string.iden), getString(R.string.iden_detail))
-            TelephonyManager.NETWORK_TYPE_EVDO_B -> arrayOf(getString(R.string.evdo_b), getString(R.string.evdo_b_detail))
-            TelephonyManager.NETWORK_TYPE_LTE -> arrayOf(getString(R.string.lte), getString(R.string.lte_detail))
-            TelephonyManager.NETWORK_TYPE_EHRPD -> arrayOf(getString(R.string.ehrpd), getString(R.string.ehrpd_detail))
-            TelephonyManager.NETWORK_TYPE_HSPAP -> arrayOf(getString(R.string.hspap), getString(R.string.hspap_detail))
-            TelephonyManager.NETWORK_TYPE_GSM -> arrayOf(getString(R.string.gsm), getString(R.string.gsm_detail))
-            TelephonyManager.NETWORK_TYPE_TD_SCDMA -> arrayOf(getString(R.string.td_scdma), getString(R.string.td_scdma_detail))
-            TelephonyManager.NETWORK_TYPE_IWLAN -> arrayOf(getString(R.string.iwlan), getString(R.string.iwlan_detail))
-            TelephonyManager.NETWORK_TYPE_NR -> arrayOf(getString(R.string.nr), getString(R.string.nr_detail))
-            else -> arrayOf(getString(R.string.error), "")
+            // Set the stingray dialog type integer.
+            overallStatusDialogTypeInt = WebViewDialog.STINGRAY
         }
-    }
 
-    private fun getAdditionalNetworkInfo(overrideNetworkType: Int) : Array<String> {
-        // Return the string that corresponds to the override network type.
-        return when(overrideNetworkType) {
-            TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE -> arrayOf(getString(R.string.none), "")
-            TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_CA -> arrayOf(getString(R.string.lte_ca), getString(R.string.lte_ca_detail))
-            TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_ADVANCED_PRO -> arrayOf(getString(R.string.lte_advanced_pro), getString(R.string.lte_advanced_pro_detail))
-            TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA -> arrayOf(getString(R.string.nr_nsa), getString(R.string.nr_nsa_detail))
-            TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA_MMWAVE -> arrayOf(getString(R.string.nr_nsa_mmwave), getString(R.string.nr_nsa_mmwave_detail))
-            else -> arrayOf(getString(R.string.error), "")
+        // Set the overall status click listener.
+        overallStatusCardView.setOnClickListener {
+            // Instantiate the stingray dialog fragment.
+            val stingrayDialogFragment = WebViewDialog().type(overallStatusDialogTypeInt)
+
+            // Show the alert dialog.
+            stingrayDialogFragment.show(supportFragmentManager, getString(R.string.stingrays))
         }
     }
-}
\ No newline at end of file
+}