2 * Copyright © 2021 Soren Stoutner <soren@stoutner.com>.
4 * This file is part of Privacy Cell <https://www.stoutner.com/privacy-cell>.
6 * Privacy Cell is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * Privacy Cell is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with Privacy Cell. If not, see <http://www.gnu.org/licenses/>.
20 package com.stoutner.privacycell.activities
22 import android.Manifest
23 import android.app.ActivityManager
24 import android.content.Context
25 import android.content.Intent
26 import android.content.pm.PackageManager
27 import android.net.Uri
28 import android.os.Bundle
29 import android.telephony.PhoneStateListener
30 import android.telephony.ServiceState
31 import android.telephony.TelephonyDisplayInfo
32 import android.telephony.TelephonyManager
33 import android.view.MenuItem
34 import android.view.View
35 import android.widget.ImageView
36 import android.widget.LinearLayout
37 import android.widget.TextView
39 import androidx.appcompat.app.ActionBar
40 import androidx.appcompat.app.ActionBarDrawerToggle
41 import androidx.appcompat.app.AppCompatActivity
42 import androidx.appcompat.content.res.AppCompatResources
43 import androidx.appcompat.widget.Toolbar
44 import androidx.core.app.ActivityCompat
45 import androidx.core.view.GravityCompat
46 import androidx.drawerlayout.widget.DrawerLayout
47 import androidx.preference.PreferenceManager
49 import com.google.android.material.navigation.NavigationView
51 import com.stoutner.privacycell.R
52 import com.stoutner.privacycell.dialogs.PhonePermissionDialog
53 import com.stoutner.privacycell.dialogs.WebViewDialog
54 import com.stoutner.privacycell.services.RealtimeMonitoringService
56 class PrivacyCellActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelectedListener, PhonePermissionDialog.StoragePermissionDialogListener {
57 // Declare the class variables.
58 private lateinit var context: Context
59 private lateinit var telephonyManager: TelephonyManager
60 private lateinit var actionBarDrawerToggle: ActionBarDrawerToggle
63 private lateinit var drawerLayout: DrawerLayout
64 private lateinit var stingrayLinearLayout: LinearLayout
65 private lateinit var stingrayImageView: ImageView
66 private lateinit var stingrayTextView: TextView
67 private lateinit var voiceNetworkLinearLayout: LinearLayout
68 private lateinit var voiceNetworkTextView: TextView
69 private lateinit var voiceNetworkDetailsTextView: TextView
70 private lateinit var dataNetworkLinearLayout: LinearLayout
71 private lateinit var dataNetworkTextView: TextView
72 private lateinit var dataNetworkDetailsTextView: TextView
73 private lateinit var additionalNetworkInfoLinearLayout: LinearLayout
74 private lateinit var additionalNetworkInfoTextView: TextView
75 private lateinit var additionalNetworkInfoDetailsTextView: TextView
77 override fun onCreate(savedInstanceState: Bundle?) {
78 // Run the default commands.
79 super.onCreate(savedInstanceState)
81 // Get a handle for the shared preferences.
82 val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this)
84 // Get the preferences.
85 val realtimeMonitoring = sharedPreferences.getBoolean(getString(R.string.realtime_monitoring_key), false)
86 val bottomAppBar = sharedPreferences.getBoolean(getString(R.string.bottom_app_bar_key), false)
88 // Set the content view.
90 setContentView(R.layout.privacy_cell_bottom_appbar)
92 setContentView(R.layout.privacy_cell_top_appbar)
95 // Get handles for the views.
96 drawerLayout = findViewById(R.id.drawerlayout)
97 val toolbar = findViewById<Toolbar>(R.id.toolbar)
98 stingrayLinearLayout = findViewById(R.id.stingray_linearlayout)
99 stingrayImageView = findViewById(R.id.stingray_imageview)
100 stingrayTextView = findViewById(R.id.stingray_textview)
101 voiceNetworkLinearLayout = findViewById(R.id.voice_network_linearlayout)
102 voiceNetworkTextView = findViewById(R.id.voice_network)
103 voiceNetworkDetailsTextView = findViewById(R.id.voice_network_details)
104 dataNetworkLinearLayout = findViewById(R.id.data_network_linearlayout)
105 dataNetworkTextView = findViewById(R.id.data_network)
106 dataNetworkDetailsTextView = findViewById(R.id.data_network_details)
107 additionalNetworkInfoLinearLayout = findViewById(R.id.additional_network_info_linearlayout)
108 additionalNetworkInfoTextView = findViewById(R.id.additional_network_info)
109 additionalNetworkInfoDetailsTextView = findViewById(R.id.additional_network_info_details)
110 val navigationView = findViewById<NavigationView>(R.id.navigationview)
112 // Get handles for the context and the telephony manager.
114 telephonyManager = getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
116 // Set the support action bar.
117 setSupportActionBar(toolbar)
119 // Get a handle for the action bar.
120 val actionBar = supportActionBar!!
122 // Set a custom view on the action bar.
123 actionBar.setCustomView(R.layout.app_bar_textview)
125 // Display the custom view.
126 actionBar.displayOptions = ActionBar.DISPLAY_SHOW_CUSTOM
128 // Define a hamburger icon at the start of the app bar. It will be populated in `onPostCreate()`.
129 actionBarDrawerToggle = ActionBarDrawerToggle(this, drawerLayout, toolbar, R.string.open_navigation_drawer, R.string.close_navigation_drawer)
131 // Listen for touches on the navigation menu.
132 navigationView.setNavigationItemSelectedListener(this)
134 // Add a drawer listener.
135 drawerLayout.addDrawerListener(object : DrawerLayout.DrawerListener {
136 override fun onDrawerSlide(drawerView: View, slideOffset: Float) {
140 override fun onDrawerOpened(drawerView: View) {
144 override fun onDrawerClosed(drawerView: View) {
145 // Reset the drawer icon when the drawer is closed. Otherwise, it is an arrow if the drawer is open when the app is restarted.
146 actionBarDrawerToggle.syncState()
149 override fun onDrawerStateChanged(newState: Int) {
154 // Start the realtime monitoring service if it is enabled.
155 if (realtimeMonitoring) {
156 // Get a handle for the activity manager.
157 val activityManager: ActivityManager = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
159 // 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.
160 val runningServiceInfoList: List<ActivityManager.RunningServiceInfo> = activityManager.getRunningServices(1)
162 // Start the service if it is not already running.
163 if (runningServiceInfoList.isEmpty()) {
164 startService(Intent(this, RealtimeMonitoringService::class.java))
169 override fun onPostCreate(savedInstanceState: Bundle?) {
170 // Run the default commands.
171 super.onPostCreate(savedInstanceState)
173 // Sync the state of the DrawerToggle after the default `onRestoreInstanceState()` has finished. This creates the navigation drawer icon.
174 actionBarDrawerToggle.syncState()
177 override fun onResume() {
178 // Run the default commands.
181 // 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.
182 if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED) { // The storage permission has been granted.
183 // Populate Privacy Cell.
184 populatePrivacyCell(this)
185 } else { // The phone permission has not been granted.
186 // Check if the user has previously denied the storage permission.
187 if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.READ_PHONE_STATE)) { // Show a dialog explaining the request first.
188 // Check to see if a phone permission dialog is already displayed. This happens if the app is restarted when the dialog is shown.
189 if (supportFragmentManager.findFragmentByTag(getString(R.string.phone_permission)) == null) { // No dialog is currently shown.
190 // Instantiate the phone permission dialog fragment.
191 val phonePermissionDialogFragment = PhonePermissionDialog()
193 // Show the phone permission alert dialog. The permission will be requested when the dialog is closed.
194 phonePermissionDialogFragment.show(supportFragmentManager, getString(R.string.phone_permission))
196 } else { // Show the permission request directly.
197 // Request the read phone state permission. There is only one permission request in the app, so it has a request code of 0.
198 ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.READ_PHONE_STATE), 0)
203 override fun onNavigationItemSelected(menuItem: MenuItem) : Boolean {
204 // Run the commands that correspond to the selected menu item.
205 when (menuItem.itemId) {
206 R.id.settings -> { // Settings.
207 // Create an intent to load the Settings activity.
208 val settingsIntent = Intent(this, SettingsActivity::class.java)
211 startActivity(settingsIntent)
214 R.id.permissions -> { // Permissions.
215 // Instantiate the permissions dialog fragment.
216 val permissionsDialogFragment = WebViewDialog().type(WebViewDialog.PERMISSIONS)
218 // Show the alert dialog.
219 permissionsDialogFragment.show(supportFragmentManager, getString(R.string.permissions))
222 R.id.privacy_policy -> { // Privacy Policy.
223 // Instantiate the privacy policy dialog fragment.
224 val privacyPolicyDialogFragment = WebViewDialog().type(WebViewDialog.PRIVACY_POLICY)
226 // Show the alert dialog.
227 privacyPolicyDialogFragment.show(supportFragmentManager, getString(R.string.privacy_policy))
230 R.id.changelog -> { // Changelog.
231 // Instantiate the changelog dialog fragment.
232 val changelogDialogFragment = WebViewDialog().type(WebViewDialog.CHANGELOG)
234 // Show the alert dialog.
235 changelogDialogFragment.show(supportFragmentManager, getString(R.string.changelog))
238 R.id.licenses -> { // Licenses.
239 // Instantiate the licenses dialog fragment.
240 val licensesDialogFragment = WebViewDialog().type(WebViewDialog.LICENSES)
242 // Show the alert dialog.
243 licensesDialogFragment.show(supportFragmentManager, getString(R.string.licenses))
246 R.id.contributors -> { // Contributors.
247 // Instantiate the contributors dialog fragment.
248 val contributorsDialogFragment = WebViewDialog().type(WebViewDialog.CONTRIBUTORS)
250 // Show the alert dialog.
251 contributorsDialogFragment.show(supportFragmentManager, getString(R.string.contributors))
254 R.id.news -> { // News.
255 // Create a news URL intent.
256 val newsUrlIntent = Intent(Intent.ACTION_VIEW)
258 // Add the URL to the intent.
259 newsUrlIntent.data = Uri.parse("https://www.stoutner.com/category/privacy-cell/")
262 startActivity(newsUrlIntent)
265 R.id.roadmap -> { // Roadmap.
266 // Create a roadmap URL intent.
267 val roadmapUrlIntent = Intent(Intent.ACTION_VIEW)
269 // Add the URL to the intent.
270 roadmapUrlIntent.data = Uri.parse("https://www.stoutner.com/category/privacy-cell-roadmap/")
273 startActivity(roadmapUrlIntent)
276 R.id.bug_tracker -> { // Bug tracker.
277 // Create a bug tracker URL intent.
278 val bugTrackerUrlIntent = Intent(Intent.ACTION_VIEW)
280 // Add the URL to the intent.
281 bugTrackerUrlIntent.data = Uri.parse("https://redmine.stoutner.com/projects/privacy-cell/issues")
284 startActivity(bugTrackerUrlIntent)
287 R.id.forum -> { // Forum.
288 // Create a forum URL intent.
289 val forumUrlIntent = Intent(Intent.ACTION_VIEW)
291 // Add the URL to the intent.
292 forumUrlIntent.data = Uri.parse("https://redmine.stoutner.com/projects/privacy-cell/boards")
295 startActivity(forumUrlIntent)
298 R.id.donations -> { // Donations.
299 // Create a donations URL intent.
300 val donationsUrlIntent = Intent(Intent.ACTION_VIEW)
302 // Add the URL to the intent.
303 donationsUrlIntent.data = Uri.parse("https://www.stoutner.com/donations/")
306 startActivity(donationsUrlIntent)
310 // Close the navigation drawer.
311 drawerLayout.closeDrawer(GravityCompat.START)
313 // Consume the click.
317 override fun onCloseStoragePermissionDialog() {
318 // Request the read phone state permission. There is only one permission request in the app, so it has a request code of 0.
319 ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.READ_PHONE_STATE), 0)
322 override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
323 // Run the default commands.
324 super.onRequestPermissionsResult(requestCode, permissions, grantResults)
326 //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).
327 if (grantResults.isNotEmpty()) {
328 // Check to see if the read phone state permission was granted. If the dialog was canceled the grant results will be empty.
329 if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { // The read phone state permission was granted.
330 // Populate Privacy Cell.
331 populatePrivacyCell(this)
332 } else { // The read phone state permission was denied.
333 // Display the phone permission text on the main activity.
334 stingrayTextView.text = getString(R.string.phone_permission_text)
339 private fun populatePrivacyCell(context: Context) {
340 // Listen to changes in the cell network state.
341 telephonyManager.listen(object : PhoneStateListener() {
342 override fun onDisplayInfoChanged(telephonyDisplayInfo: TelephonyDisplayInfo) {
343 // Populate the stingray security information. <https://source.android.com/devices/tech/connect/acts-5g-testing>
344 if (telephonyDisplayInfo.networkType == TelephonyManager.NETWORK_TYPE_NR) { // This is a secure 5G NR SA network.
345 // Populate the image view.
346 stingrayImageView.setImageDrawable(AppCompatResources.getDrawable(context, R.drawable.secure_5g_nr_sa))
349 stingrayTextView.text = getString(R.string.secure_from_stingray)
351 // Set the text color.
352 stingrayTextView.setTextColor(getColor(R.color.blue_text))
353 } else { // This is not a secure 5G NR SA network.
354 // Populate the image view.
355 stingrayImageView.setImageDrawable(AppCompatResources.getDrawable(context, R.drawable.not_secure))
358 stingrayTextView.text = getString(R.string.not_secure_from_stingray)
360 // Set the text color.
361 stingrayTextView.setTextColor(getColor(R.color.red_text))
364 // Get the strings that correspond to the network information.
365 val dataNetworkType = getNetworkType(telephonyDisplayInfo.networkType)
366 val additionalNetworkInfo = getAdditionalNetworkInfo(telephonyDisplayInfo.overrideNetworkType)
368 // Populate the data network text views.
369 dataNetworkTextView.text = getString(R.string.data_network, dataNetworkType[0])
370 dataNetworkDetailsTextView.text = dataNetworkType[1]
371 additionalNetworkInfoTextView.text = getString(R.string.additional_network_info, additionalNetworkInfo[0])
372 additionalNetworkInfoDetailsTextView.text = additionalNetworkInfo[1]
374 // Set the stingray click listener.
375 stingrayLinearLayout.setOnClickListener {
376 // Instantiate the stingray dialog fragment.
377 val stingrayDialogFragment = WebViewDialog().type(WebViewDialog.STINGRAY)
379 // Show the alert dialog.
380 stingrayDialogFragment.show(supportFragmentManager, getString(R.string.stingrays))
383 // Set the data network click listener.
384 dataNetworkLinearLayout.setOnClickListener {
385 // Instantiate the data network dialog fragment according to the network type.
386 val dataNetworkDialogFragment = when (telephonyDisplayInfo.networkType) {
387 TelephonyManager.NETWORK_TYPE_UNKNOWN -> WebViewDialog().type(WebViewDialog.NETWORK_UNKNOWN)
388 TelephonyManager.NETWORK_TYPE_GPRS -> WebViewDialog().type(WebViewDialog.NETWORK_GPRS)
389 TelephonyManager.NETWORK_TYPE_EDGE -> WebViewDialog().type(WebViewDialog.NETWORK_EDGE)
390 TelephonyManager.NETWORK_TYPE_UMTS -> WebViewDialog().type(WebViewDialog.NETWORK_UMTS)
391 TelephonyManager.NETWORK_TYPE_CDMA -> WebViewDialog().type(WebViewDialog.NETWORK_CDMA)
392 TelephonyManager.NETWORK_TYPE_EVDO_0 -> WebViewDialog().type(WebViewDialog.NETWORK_EVDO_0)
393 TelephonyManager.NETWORK_TYPE_EVDO_A -> WebViewDialog().type(WebViewDialog.NETWORK_EVDO_A)
394 TelephonyManager.NETWORK_TYPE_1xRTT -> WebViewDialog().type(WebViewDialog.NETWORK_1xRTT)
395 TelephonyManager.NETWORK_TYPE_HSDPA -> WebViewDialog().type(WebViewDialog.NETWORK_HSDPA)
396 TelephonyManager.NETWORK_TYPE_HSUPA -> WebViewDialog().type(WebViewDialog.NETWORK_HSUPA)
397 TelephonyManager.NETWORK_TYPE_HSPA -> WebViewDialog().type(WebViewDialog.NETWORK_HSPA)
398 TelephonyManager.NETWORK_TYPE_IDEN -> WebViewDialog().type(WebViewDialog.NETWORK_IDEN)
399 TelephonyManager.NETWORK_TYPE_EVDO_B -> WebViewDialog().type(WebViewDialog.NETWORK_EVDO_B)
400 TelephonyManager.NETWORK_TYPE_LTE -> WebViewDialog().type(WebViewDialog.NETWORK_LTE)
401 TelephonyManager.NETWORK_TYPE_EHRPD -> WebViewDialog().type(WebViewDialog.NETWORK_EHRPD)
402 TelephonyManager.NETWORK_TYPE_HSPAP -> WebViewDialog().type(WebViewDialog.NETWORK_HSPAP)
403 TelephonyManager.NETWORK_TYPE_GSM -> WebViewDialog().type(WebViewDialog.NETWORK_GSM)
404 TelephonyManager.NETWORK_TYPE_TD_SCDMA -> WebViewDialog().type(WebViewDialog.NETWORK_TD_SCDMA)
405 TelephonyManager.NETWORK_TYPE_IWLAN -> WebViewDialog().type(WebViewDialog.NETWORK_IWLAN)
406 TelephonyManager.NETWORK_TYPE_NR -> WebViewDialog().type(WebViewDialog.NETWORK_NR)
407 else -> WebViewDialog().type(WebViewDialog.NETWORK_UNKNOWN)
410 // Show the alert dialog.
411 dataNetworkDialogFragment.show(supportFragmentManager, getString(R.string.voice_network))
414 // Set the additional network info click listener.
415 additionalNetworkInfoLinearLayout.setOnClickListener {
416 // Instantiate the initial network info dialog fragment according to the network type.
417 val additionalNetworkInfoDialogFragment = when (telephonyDisplayInfo.overrideNetworkType) {
418 TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE -> WebViewDialog().type(WebViewDialog.OVERRIDE_NETWORK_NONE)
419 TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_CA -> WebViewDialog().type(WebViewDialog.OVERRIDE_NETWORK_LTE_CA)
420 TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_ADVANCED_PRO -> WebViewDialog().type(WebViewDialog.OVERRIDE_NETWORK_LTE_ADVANCED_PRO)
421 TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA -> WebViewDialog().type(WebViewDialog.OVERRIDE_NETWORK_NR_NSA)
422 TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA_MMWAVE -> WebViewDialog().type(WebViewDialog.OVERRIDE_NETWORK_NR_NSA_MMWAVE)
423 else -> WebViewDialog().type(WebViewDialog.OVERRIDE_NETWORK_NR_NSA_MMWAVE)
426 // Show the alert dialog.
427 additionalNetworkInfoDialogFragment.show(supportFragmentManager, getString(R.string.voice_network))
431 override fun onServiceStateChanged(serviceState: ServiceState) {
432 // 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).
433 val networkRegistrationInfo = serviceState.networkRegistrationInfoList[1]
435 // Get the voice network type.
436 val voiceNetworkType = getNetworkType(networkRegistrationInfo.accessNetworkTechnology)
438 // Populate the voice network text views.
439 voiceNetworkTextView.text = getString(R.string.voice_network, voiceNetworkType[0])
440 voiceNetworkDetailsTextView.text = voiceNetworkType[1]
442 // Set the voice network click listener.
443 voiceNetworkLinearLayout.setOnClickListener {
444 // Instantiate the voice network dialog fragment according to the network type.
445 val voiceNetworkDialogFragment = when (networkRegistrationInfo.accessNetworkTechnology) {
446 TelephonyManager.NETWORK_TYPE_UNKNOWN -> WebViewDialog().type(WebViewDialog.NETWORK_UNKNOWN)
447 TelephonyManager.NETWORK_TYPE_GPRS -> WebViewDialog().type(WebViewDialog.NETWORK_GPRS)
448 TelephonyManager.NETWORK_TYPE_EDGE -> WebViewDialog().type(WebViewDialog.NETWORK_EDGE)
449 TelephonyManager.NETWORK_TYPE_UMTS -> WebViewDialog().type(WebViewDialog.NETWORK_UMTS)
450 TelephonyManager.NETWORK_TYPE_CDMA -> WebViewDialog().type(WebViewDialog.NETWORK_CDMA)
451 TelephonyManager.NETWORK_TYPE_EVDO_0 -> WebViewDialog().type(WebViewDialog.NETWORK_EVDO_0)
452 TelephonyManager.NETWORK_TYPE_EVDO_A -> WebViewDialog().type(WebViewDialog.NETWORK_EVDO_A)
453 TelephonyManager.NETWORK_TYPE_1xRTT -> WebViewDialog().type(WebViewDialog.NETWORK_1xRTT)
454 TelephonyManager.NETWORK_TYPE_HSDPA -> WebViewDialog().type(WebViewDialog.NETWORK_HSDPA)
455 TelephonyManager.NETWORK_TYPE_HSUPA -> WebViewDialog().type(WebViewDialog.NETWORK_HSUPA)
456 TelephonyManager.NETWORK_TYPE_HSPA -> WebViewDialog().type(WebViewDialog.NETWORK_HSPA)
457 TelephonyManager.NETWORK_TYPE_IDEN -> WebViewDialog().type(WebViewDialog.NETWORK_IDEN)
458 TelephonyManager.NETWORK_TYPE_EVDO_B -> WebViewDialog().type(WebViewDialog.NETWORK_EVDO_B)
459 TelephonyManager.NETWORK_TYPE_LTE -> WebViewDialog().type(WebViewDialog.NETWORK_LTE)
460 TelephonyManager.NETWORK_TYPE_EHRPD -> WebViewDialog().type(WebViewDialog.NETWORK_EHRPD)
461 TelephonyManager.NETWORK_TYPE_HSPAP -> WebViewDialog().type(WebViewDialog.NETWORK_HSPAP)
462 TelephonyManager.NETWORK_TYPE_GSM -> WebViewDialog().type(WebViewDialog.NETWORK_GSM)
463 TelephonyManager.NETWORK_TYPE_TD_SCDMA -> WebViewDialog().type(WebViewDialog.NETWORK_TD_SCDMA)
464 TelephonyManager.NETWORK_TYPE_IWLAN -> WebViewDialog().type(WebViewDialog.NETWORK_IWLAN)
465 TelephonyManager.NETWORK_TYPE_NR -> WebViewDialog().type(WebViewDialog.NETWORK_NR)
466 else -> WebViewDialog().type(WebViewDialog.NETWORK_UNKNOWN)
469 // Show the alert dialog.
470 voiceNetworkDialogFragment.show(supportFragmentManager, getString(R.string.voice_network))
473 }, PhoneStateListener.LISTEN_DISPLAY_INFO_CHANGED or PhoneStateListener.LISTEN_SERVICE_STATE)
476 private fun getNetworkType(networkType: Int) : Array<String> {
477 // Return the string that corresponds to the network type.
478 return when(networkType) {
479 TelephonyManager.NETWORK_TYPE_UNKNOWN -> arrayOf(getString(R.string.unknown), "")
480 TelephonyManager.NETWORK_TYPE_GPRS -> arrayOf(getString(R.string.gprs), getString(R.string.gprs_detail))
481 TelephonyManager.NETWORK_TYPE_EDGE -> arrayOf(getString(R.string.edge), getString(R.string.edge_detail))
482 TelephonyManager.NETWORK_TYPE_UMTS -> arrayOf(getString(R.string.umts), getString(R.string.umts_detail))
483 TelephonyManager.NETWORK_TYPE_CDMA -> arrayOf(getString(R.string.cdma), getString(R.string.cdma_detail))
484 TelephonyManager.NETWORK_TYPE_EVDO_0 -> arrayOf(getString(R.string.evdo_0), getString(R.string.evdo_0_detail))
485 TelephonyManager.NETWORK_TYPE_EVDO_A -> arrayOf(getString(R.string.evdo_a), getString(R.string.evdo_a_detail))
486 TelephonyManager.NETWORK_TYPE_1xRTT -> arrayOf(getString(R.string.rtt), getString(R.string.rtt_detail))
487 TelephonyManager.NETWORK_TYPE_HSDPA -> arrayOf(getString(R.string.hsdpa), getString(R.string.hsdpa_detail))
488 TelephonyManager.NETWORK_TYPE_HSUPA -> arrayOf(getString(R.string.hsupa), getString(R.string.hsupa_detail))
489 TelephonyManager.NETWORK_TYPE_HSPA -> arrayOf(getString(R.string.hspa), getString(R.string.hspa_detail))
490 TelephonyManager.NETWORK_TYPE_IDEN -> arrayOf(getString(R.string.iden), getString(R.string.iden_detail))
491 TelephonyManager.NETWORK_TYPE_EVDO_B -> arrayOf(getString(R.string.evdo_b), getString(R.string.evdo_b_detail))
492 TelephonyManager.NETWORK_TYPE_LTE -> arrayOf(getString(R.string.lte), getString(R.string.lte_detail))
493 TelephonyManager.NETWORK_TYPE_EHRPD -> arrayOf(getString(R.string.ehrpd), getString(R.string.ehrpd_detail))
494 TelephonyManager.NETWORK_TYPE_HSPAP -> arrayOf(getString(R.string.hspap), getString(R.string.hspap_detail))
495 TelephonyManager.NETWORK_TYPE_GSM -> arrayOf(getString(R.string.gsm), getString(R.string.gsm_detail))
496 TelephonyManager.NETWORK_TYPE_TD_SCDMA -> arrayOf(getString(R.string.td_scdma), getString(R.string.td_scdma_detail))
497 TelephonyManager.NETWORK_TYPE_IWLAN -> arrayOf(getString(R.string.iwlan), getString(R.string.iwlan_detail))
498 TelephonyManager.NETWORK_TYPE_NR -> arrayOf(getString(R.string.nr), getString(R.string.nr_detail))
499 else -> arrayOf(getString(R.string.error), "")
503 private fun getAdditionalNetworkInfo(overrideNetworkType: Int) : Array<String> {
504 // Return the string that corresponds to the override network type.
505 return when(overrideNetworkType) {
506 TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE -> arrayOf(getString(R.string.none), "")
507 TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_CA -> arrayOf(getString(R.string.lte_ca), getString(R.string.lte_ca_detail))
508 TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_ADVANCED_PRO -> arrayOf(getString(R.string.lte_advanced_pro), getString(R.string.lte_advanced_pro_detail))
509 TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA -> arrayOf(getString(R.string.nr_nsa), getString(R.string.nr_nsa_detail))
510 TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA_MMWAVE -> arrayOf(getString(R.string.nr_nsa_mmwave), getString(R.string.nr_nsa_mmwave_detail))
511 else -> arrayOf(getString(R.string.error), "")