/* * Copyright 2021-2022 Soren Stoutner . * * This file is part of 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. * * 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. * * You should have received a copy of the GNU General Public License * along with Privacy Cell. If not, see . */ // 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.Bundle import android.telephony.PhoneStateListener // This can be replaced by `TelephonyCallback` once the minimum API >= 31. import android.telephony.ServiceState import android.telephony.TelephonyDisplayInfo import android.telephony.TelephonyManager import android.view.MenuItem import android.view.View import android.widget.ImageView import android.widget.LinearLayout import android.widget.TextView import androidx.appcompat.app.ActionBar import androidx.appcompat.app.ActionBarDrawerToggle import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.content.res.AppCompatResources import androidx.appcompat.widget.Toolbar import androidx.core.app.ActivityCompat import androidx.core.view.GravityCompat import androidx.drawerlayout.widget.DrawerLayout import androidx.preference.PreferenceManager 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 // Declare the class variables. private lateinit var phoneStateListener: PhoneStateListener // The `PhoneStateListener` can be replaced by `TelephonyCallback` once the minimum API >= 31. // Declare the class views. private lateinit var actionBarDrawerToggle: ActionBarDrawerToggle private lateinit var drawerLayout: DrawerLayout private lateinit var overallStatusLinearLayout: LinearLayout 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. super.onCreate(savedInstanceState) // Get a handle for the shared preferences. val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this) // 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. if (bottomAppBar) { setContentView(R.layout.privacy_cell_bottom_appbar) } else { setContentView(R.layout.privacy_cell_top_appbar) } // Get handles for the views. drawerLayout = findViewById(R.id.drawerlayout) val toolbar = findViewById(R.id.toolbar) overallStatusLinearLayout = findViewById(R.id.overall_status_linearlayout) overallStatusImageView = findViewById(R.id.overall_status_imageview) overallStatusTextView = findViewById(R.id.overall_status_textview) val voiceNetworkLinearLayout = findViewById(R.id.voice_network_linearlayout) val voiceNetworkTextView = findViewById(R.id.voice_network) val voiceNetworkDetailsTextView = findViewById(R.id.voice_network_details) val dataNetworkLinearLayout = findViewById(R.id.data_network_linearlayout) val dataNetworkTextView = findViewById(R.id.data_network) val dataNetworkDetailsTextView = findViewById(R.id.data_network_details) val additionalNetworkInfoLinearLayout = findViewById(R.id.additional_network_info_linearlayout) val additionalNetworkInfoTextView = findViewById(R.id.additional_network_info) val additionalNetworkInfoDetailsTextView = findViewById(R.id.additional_network_info_details) val navigationView = findViewById(R.id.navigationview) // Set the support action bar. setSupportActionBar(toolbar) // Get a handle for the action bar. val actionBar = supportActionBar!! // Set a custom view on the action bar. actionBar.setCustomView(R.layout.app_bar_textview) // Display the custom view. actionBar.displayOptions = ActionBar.DISPLAY_SHOW_CUSTOM // Define a hamburger icon at the start of the app bar. It will be populated in `onPostCreate()`. actionBarDrawerToggle = ActionBarDrawerToggle(this, drawerLayout, toolbar, R.string.open_navigation_drawer, R.string.close_navigation_drawer) // Listen for touches on the navigation menu. navigationView.setNavigationItemSelectedListener(this) // Add a drawer listener. drawerLayout.addDrawerListener(object : DrawerLayout.DrawerListener { override fun onDrawerSlide(drawerView: View, slideOffset: Float) { // Do nothing. } override fun onDrawerOpened(drawerView: View) { // Do nothing. } override fun onDrawerClosed(drawerView: View) { // Reset the drawer icon when the drawer is closed. Otherwise, it is an arrow if the drawer is open when the app is restarted. actionBarDrawerToggle.syncState() } override fun onDrawerStateChanged(newState: Int) { // Do nothing. } }) // Instantiate the protocol helper. val protocolHelper = ProtocolHelper() // 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) // Populate the voice network text views. voiceNetworkTextView.text = getString(R.string.voice_network, voiceNetworkStringArray[0]) voiceNetworkDetailsTextView.text = voiceNetworkStringArray[1] // 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. voiceNetworkLinearLayout.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. 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) // Populate the data network text views. dataNetworkTextView.text = getString(R.string.data_network, dataNetworkStringArray[0]) dataNetworkDetailsTextView.text = dataNetworkStringArray[1] 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.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?) { // 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. actionBarDrawerToggle.syncState() } override fun onStart() { // Run the default commands. super.onStart() // 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) { // The storage permission has 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 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() // Show the phone permission alert dialog. The permission will be requested when the dialog is closed. phonePermissionDialogFragment.show(supportFragmentManager, getString(R.string.phone_permission)) } } else { // Show the permission request directly. // Request the read phone state permission. ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.READ_PHONE_STATE), 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) { R.id.settings -> { // Settings. // Create an intent to load the Settings activity. val settingsIntent = Intent(this, SettingsActivity::class.java) // Make it so. 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) // Show the alert dialog. permissionsDialogFragment.show(supportFragmentManager, getString(R.string.permissions)) } R.id.privacy_policy -> { // Privacy Policy. // Instantiate the privacy policy dialog fragment. val privacyPolicyDialogFragment = WebViewDialog().type(WebViewDialog.PRIVACY_POLICY) // Show the alert dialog. privacyPolicyDialogFragment.show(supportFragmentManager, getString(R.string.privacy_policy)) } R.id.changelog -> { // Changelog. // Instantiate the changelog dialog fragment. val changelogDialogFragment = WebViewDialog().type(WebViewDialog.CHANGELOG) // Show the alert dialog. changelogDialogFragment.show(supportFragmentManager, getString(R.string.changelog)) } R.id.licenses -> { // Licenses. // Instantiate the licenses dialog fragment. val licensesDialogFragment = WebViewDialog().type(WebViewDialog.LICENSES) // Show the alert dialog. licensesDialogFragment.show(supportFragmentManager, getString(R.string.licenses)) } R.id.contributors -> { // Contributors. // Instantiate the contributors dialog fragment. val contributorsDialogFragment = WebViewDialog().type(WebViewDialog.CONTRIBUTORS) // Show the alert dialog. contributorsDialogFragment.show(supportFragmentManager, getString(R.string.contributors)) } R.id.news -> { // News. // Create a news URL intent. val newsUrlIntent = Intent(Intent.ACTION_VIEW) // Add the URL to the intent. newsUrlIntent.data = Uri.parse("https://www.stoutner.com/category/privacy-cell/") // Make it so. startActivity(newsUrlIntent) } R.id.roadmap -> { // Roadmap. // Create a roadmap URL intent. val roadmapUrlIntent = Intent(Intent.ACTION_VIEW) // Add the URL to the intent. roadmapUrlIntent.data = Uri.parse("https://www.stoutner.com/category/privacy-cell-roadmap/") // Make it so. startActivity(roadmapUrlIntent) } R.id.bug_tracker -> { // Bug tracker. // Create a bug tracker URL intent. val bugTrackerUrlIntent = Intent(Intent.ACTION_VIEW) // Add the URL to the intent. bugTrackerUrlIntent.data = Uri.parse("https://redmine.stoutner.com/projects/privacy-cell/issues") // Make it so. startActivity(bugTrackerUrlIntent) } R.id.forum -> { // Forum. // Create a forum URL intent. val forumUrlIntent = Intent(Intent.ACTION_VIEW) // Add the URL to the intent. forumUrlIntent.data = Uri.parse("https://redmine.stoutner.com/projects/privacy-cell/boards") // Make it so. startActivity(forumUrlIntent) } R.id.donations -> { // Donations. // Create a donations URL intent. val donationsUrlIntent = Intent(Intent.ACTION_VIEW) // Add the URL to the intent. donationsUrlIntent.data = Uri.parse("https://www.stoutner.com/donations/") // Make it so. startActivity(donationsUrlIntent) } } // Close the navigation drawer. drawerLayout.closeDrawer(GravityCompat.START) // Consume the click. return true } override fun onCloseStoragePermissionDialog() { // 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, 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) 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. registerTelephonyManagerListener() } else { // The read phone state permission was denied. // Display the phone permission text on the main activity. overallStatusTextView.text = getString(R.string.phone_permission_text) } } } private fun registerTelephonyManagerListener() { // Get a handle for the telephony manager. val telephonyManager = getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager // 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) } private fun populateOverallSecurityStatus() { // Create an overall status dialog type integer. val overallStatusDialogTypeInt: Int // 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)) // Set the text. overallStatusTextView.text = getString(R.string.antiquated_protocols) // Set the text color. overallStatusTextView.setTextColor(getColor(R.color.red_text)) // 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)) // Set the text. overallStatusTextView.text = getString(R.string.insecure_protocols) // Set the text color. overallStatusTextView.setTextColor(getColor(R.color.yellow_text)) // 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 text. overallStatusTextView.text = getString(R.string.secure_protocols) // Set the text color. overallStatusTextView.setTextColor(getColor(R.color.blue_text)) // Set the stingray dialog type integer. overallStatusDialogTypeInt = WebViewDialog.STINGRAY } // Set the overall status click listener. overallStatusLinearLayout.setOnClickListener { // Instantiate the stingray dialog fragment. val stingrayDialogFragment = WebViewDialog().type(overallStatusDialogTypeInt) // Show the alert dialog. stingrayDialogFragment.show(supportFragmentManager, getString(R.string.stingrays)) } } }