]> gitweb.stoutner.com Git - PrivacyCell.git/blob - app/src/main/java/com/stoutner/privacycell/activities/PrivacyCellActivity.kt
Improve logic for turning off realtime monitoring. https://redmine.stoutner.com/issue...
[PrivacyCell.git] / app / src / main / java / com / stoutner / privacycell / activities / PrivacyCellActivity.kt
1 /*
2  * Copyright © 2021-2022 Soren Stoutner <soren@stoutner.com>.
3  *
4  * This file is part of Privacy Cell <https://www.stoutner.com/privacy-cell>.
5  *
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.
10  *
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.
15  *
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/>.
18  */
19
20 // The suppression of deprecation lint can be removed once the minimum API >= 31.
21 @file:Suppress("DEPRECATION")
22
23 package com.stoutner.privacycell.activities
24
25 import android.Manifest
26 import android.annotation.SuppressLint
27 import android.app.ActivityManager
28 import android.content.Context
29 import android.content.Intent
30 import android.content.pm.PackageManager
31 import android.net.Uri
32 import android.os.Bundle
33 import android.telephony.PhoneStateListener  // This can be replaced by `TelephonyCallback` once the minimum API >= 31.
34 import android.telephony.ServiceState
35 import android.telephony.TelephonyDisplayInfo
36 import android.telephony.TelephonyManager
37 import android.view.MenuItem
38 import android.view.View
39 import android.widget.ImageView
40 import android.widget.LinearLayout
41 import android.widget.TextView
42
43 import androidx.appcompat.app.ActionBar
44 import androidx.appcompat.app.ActionBarDrawerToggle
45 import androidx.appcompat.app.AppCompatActivity
46 import androidx.appcompat.content.res.AppCompatResources
47 import androidx.appcompat.widget.Toolbar
48 import androidx.core.app.ActivityCompat
49 import androidx.core.view.GravityCompat
50 import androidx.drawerlayout.widget.DrawerLayout
51 import androidx.preference.PreferenceManager
52
53 import com.google.android.material.navigation.NavigationView
54
55 import com.stoutner.privacycell.R
56 import com.stoutner.privacycell.dialogs.PhonePermissionDialog
57 import com.stoutner.privacycell.dialogs.WebViewDialog
58 import com.stoutner.privacycell.services.RealtimeMonitoringService
59
60 class PrivacyCellActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelectedListener, PhonePermissionDialog.StoragePermissionDialogListener {
61     // Declare the class variables.
62     private lateinit var actionBarDrawerToggle: ActionBarDrawerToggle
63     private lateinit var phoneStateListener: PhoneStateListener  // The `PhoneStateListener` can be replaced by `TelephonyCallback` once the minimum API >= 31.
64
65     // Declare the class views.
66     private lateinit var drawerLayout: DrawerLayout
67     private lateinit var summaryTextView: TextView
68
69     override fun onCreate(savedInstanceState: Bundle?) {
70         // Run the default commands.
71         super.onCreate(savedInstanceState)
72
73         // Get a handle for the shared preferences.
74         val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this)
75
76         // Get the preferences.
77         val realtimeMonitoring = sharedPreferences.getBoolean(getString(R.string.realtime_monitoring_key), false)
78         val consider3gAntiquated = sharedPreferences.getBoolean(getString(R.string.consider_3g_antiquated_key), false)
79         val bottomAppBar = sharedPreferences.getBoolean(getString(R.string.bottom_app_bar_key), false)
80
81         // Set the content view.
82         if (bottomAppBar) {
83             setContentView(R.layout.privacy_cell_bottom_appbar)
84         } else {
85             setContentView(R.layout.privacy_cell_top_appbar)
86         }
87
88         // Get handles for the views.
89         drawerLayout = findViewById(R.id.drawerlayout)
90         val toolbar = findViewById<Toolbar>(R.id.toolbar)
91         val stingrayLinearLayout = findViewById<LinearLayout>(R.id.stingray_linearlayout)
92         val stingrayImageView = findViewById<ImageView>(R.id.stingray_imageview)
93         summaryTextView = findViewById(R.id.summary_textview)
94         val voiceNetworkLinearLayout = findViewById<LinearLayout>(R.id.voice_network_linearlayout)
95         val voiceNetworkTextView = findViewById<TextView>(R.id.voice_network)
96         val voiceNetworkDetailsTextView = findViewById<TextView>(R.id.voice_network_details)
97         val dataNetworkLinearLayout = findViewById<LinearLayout>(R.id.data_network_linearlayout)
98         val dataNetworkTextView = findViewById<TextView>(R.id.data_network)
99         val dataNetworkDetailsTextView = findViewById<TextView>(R.id.data_network_details)
100         val additionalNetworkInfoLinearLayout = findViewById<LinearLayout>(R.id.additional_network_info_linearlayout)
101         val additionalNetworkInfoTextView = findViewById<TextView>(R.id.additional_network_info)
102         val additionalNetworkInfoDetailsTextView = findViewById<TextView>(R.id.additional_network_info_details)
103         val navigationView = findViewById<NavigationView>(R.id.navigationview)
104
105         // Set the support action bar.
106         setSupportActionBar(toolbar)
107
108         // Get a handle for the action bar.
109         val actionBar = supportActionBar!!
110
111         // Set a custom view on the action bar.
112         actionBar.setCustomView(R.layout.app_bar_textview)
113
114         // Display the custom view.
115         actionBar.displayOptions = ActionBar.DISPLAY_SHOW_CUSTOM
116
117         // Define a hamburger icon at the start of the app bar.  It will be populated in `onPostCreate()`.
118         actionBarDrawerToggle = ActionBarDrawerToggle(this, drawerLayout, toolbar, R.string.open_navigation_drawer, R.string.close_navigation_drawer)
119
120         // Listen for touches on the navigation menu.
121         navigationView.setNavigationItemSelectedListener(this)
122
123         // Add a drawer listener.
124         drawerLayout.addDrawerListener(object : DrawerLayout.DrawerListener {
125             override fun onDrawerSlide(drawerView: View, slideOffset: Float) {
126                 // Do nothing.
127             }
128
129             override fun onDrawerOpened(drawerView: View) {
130                 // Do nothing.
131             }
132
133             override fun onDrawerClosed(drawerView: View) {
134                 // Reset the drawer icon when the drawer is closed.  Otherwise, it is an arrow if the drawer is open when the app is restarted.
135                 actionBarDrawerToggle.syncState()
136             }
137
138             override fun onDrawerStateChanged(newState: Int) {
139                 // Do nothing.
140             }
141         })
142
143         // Define the phone state listener.  The `PhoneStateListener` can be replaced by `TelephonyCallback` once the minimum API >= 31.
144         phoneStateListener = object : PhoneStateListener() {
145             @Deprecated("Deprecated in Java")
146             @SuppressLint("SwitchIntDef")
147             override fun onDisplayInfoChanged(telephonyDisplayInfo: TelephonyDisplayInfo) {
148                 // Declare the stingray dialog type integer.
149                 val summaryDialogTypeInteger: Int
150
151                 // Populate the stingray security information.  <https://source.android.com/devices/tech/connect/acts-5g-testing>
152                 if ((telephonyDisplayInfo.networkType == TelephonyManager.NETWORK_TYPE_NR) || (telephonyDisplayInfo.networkType == TelephonyManager.NETWORK_TYPE_IWLAN) ||
153                     (telephonyDisplayInfo.networkType == TelephonyManager.NETWORK_TYPE_UNKNOWN)) {  // This is a secure network.
154                     // Populate the image view.
155                     stingrayImageView.setImageDrawable(AppCompatResources.getDrawable(applicationContext, R.drawable.secure))
156
157                     // Set the text.
158                     summaryTextView.text = getString(R.string.secure_protocols)
159
160                     // Set the text color.
161                     summaryTextView.setTextColor(getColor(R.color.blue_text))
162
163                     // Set the stingray dialog type integer.
164                     summaryDialogTypeInteger = WebViewDialog.STINGRAY
165                 } else if ((telephonyDisplayInfo.networkType == TelephonyManager.NETWORK_TYPE_LTE) || (!consider3gAntiquated && (telephonyDisplayInfo.networkType == TelephonyManager.NETWORK_TYPE_1xRTT ||
166                             (telephonyDisplayInfo.networkType == TelephonyManager.NETWORK_TYPE_EVDO_0) || (telephonyDisplayInfo.networkType == TelephonyManager.NETWORK_TYPE_EVDO_A) ||
167                             (telephonyDisplayInfo.networkType == TelephonyManager.NETWORK_TYPE_EVDO_B) || (telephonyDisplayInfo.networkType == TelephonyManager.NETWORK_TYPE_EHRPD) ||
168                             (telephonyDisplayInfo.networkType == TelephonyManager.NETWORK_TYPE_UMTS) || (telephonyDisplayInfo.networkType == TelephonyManager.NETWORK_TYPE_TD_SCDMA) ||
169                             (telephonyDisplayInfo.networkType == TelephonyManager.NETWORK_TYPE_HSDPA) || (telephonyDisplayInfo.networkType == TelephonyManager.NETWORK_TYPE_HSUPA) ||
170                             (telephonyDisplayInfo.networkType == TelephonyManager.NETWORK_TYPE_HSPA) || (telephonyDisplayInfo.networkType == TelephonyManager.NETWORK_TYPE_HSPAP)))) {
171                             // This is an insecure network.
172                     // Populate the image view.
173                     stingrayImageView.setImageDrawable(AppCompatResources.getDrawable(applicationContext, R.drawable.insecure))
174
175                     // Set the text.
176                     summaryTextView.text = getString(R.string.insecure_protocols)
177
178                     // Set the text color.
179                     summaryTextView.setTextColor(getColor(R.color.yellow_900))
180
181                     // Set the stingray dialog type integer.
182                     summaryDialogTypeInteger = WebViewDialog.STINGRAY
183                 } else {  // This is an antiquated network.
184                     // Populate the image view.
185                     stingrayImageView.setImageDrawable(AppCompatResources.getDrawable(applicationContext, R.drawable.antiquated))
186
187                     // Set the text.
188                     summaryTextView.text = getString(R.string.antiquated_protocols)
189
190                     // Set the text color.
191                     summaryTextView.setTextColor(getColor(R.color.red_text))
192
193                     // Set the stingray dialog type integer.
194                     summaryDialogTypeInteger = WebViewDialog.ANTIQUATED_NETWORK
195                 }
196
197                 // Get the strings that correspond to the network information.
198                 val dataNetworkType = getNetworkType(telephonyDisplayInfo.networkType)
199                 val additionalNetworkInfo = getAdditionalNetworkInfo(telephonyDisplayInfo.overrideNetworkType)
200
201                 // Populate the data network text views.
202                 dataNetworkTextView.text = getString(R.string.data_network, dataNetworkType[0])
203                 dataNetworkDetailsTextView.text = dataNetworkType[1]
204                 additionalNetworkInfoTextView.text = getString(R.string.additional_network_info, additionalNetworkInfo[0])
205                 additionalNetworkInfoDetailsTextView.text = additionalNetworkInfo[1]
206
207                 // Set the stingray click listener.
208                 stingrayLinearLayout.setOnClickListener {
209                     // Instantiate the stingray dialog fragment.
210                     val stingrayDialogFragment = WebViewDialog().type(summaryDialogTypeInteger)
211
212                     // Show the alert dialog.
213                     stingrayDialogFragment.show(supportFragmentManager, getString(R.string.stingrays))
214                 }
215
216                 // Set the data network click listener.
217                 dataNetworkLinearLayout.setOnClickListener {
218                     // Instantiate the data network dialog fragment according to the network type.
219                     val dataNetworkDialogFragment = when (telephonyDisplayInfo.networkType) {
220                         TelephonyManager.NETWORK_TYPE_UNKNOWN -> WebViewDialog().type(WebViewDialog.NETWORK_UNKNOWN)
221                         TelephonyManager.NETWORK_TYPE_GPRS -> WebViewDialog().type(WebViewDialog.NETWORK_GPRS)
222                         TelephonyManager.NETWORK_TYPE_EDGE -> WebViewDialog().type(WebViewDialog.NETWORK_EDGE)
223                         TelephonyManager.NETWORK_TYPE_UMTS -> WebViewDialog().type(WebViewDialog.NETWORK_UMTS)
224                         TelephonyManager.NETWORK_TYPE_CDMA -> WebViewDialog().type(WebViewDialog.NETWORK_CDMA)
225                         TelephonyManager.NETWORK_TYPE_EVDO_0 -> WebViewDialog().type(WebViewDialog.NETWORK_EVDO_0)
226                         TelephonyManager.NETWORK_TYPE_EVDO_A -> WebViewDialog().type(WebViewDialog.NETWORK_EVDO_A)
227                         TelephonyManager.NETWORK_TYPE_1xRTT -> WebViewDialog().type(WebViewDialog.NETWORK_1xRTT)
228                         TelephonyManager.NETWORK_TYPE_HSDPA -> WebViewDialog().type(WebViewDialog.NETWORK_HSDPA)
229                         TelephonyManager.NETWORK_TYPE_HSUPA -> WebViewDialog().type(WebViewDialog.NETWORK_HSUPA)
230                         TelephonyManager.NETWORK_TYPE_HSPA -> WebViewDialog().type(WebViewDialog.NETWORK_HSPA)
231                         TelephonyManager.NETWORK_TYPE_IDEN -> WebViewDialog().type(WebViewDialog.NETWORK_IDEN)
232                         TelephonyManager.NETWORK_TYPE_EVDO_B -> WebViewDialog().type(WebViewDialog.NETWORK_EVDO_B)
233                         TelephonyManager.NETWORK_TYPE_LTE -> WebViewDialog().type(WebViewDialog.NETWORK_LTE)
234                         TelephonyManager.NETWORK_TYPE_EHRPD -> WebViewDialog().type(WebViewDialog.NETWORK_EHRPD)
235                         TelephonyManager.NETWORK_TYPE_HSPAP -> WebViewDialog().type(WebViewDialog.NETWORK_HSPAP)
236                         TelephonyManager.NETWORK_TYPE_GSM -> WebViewDialog().type(WebViewDialog.NETWORK_GSM)
237                         TelephonyManager.NETWORK_TYPE_TD_SCDMA -> WebViewDialog().type(WebViewDialog.NETWORK_TD_SCDMA)
238                         TelephonyManager.NETWORK_TYPE_IWLAN -> WebViewDialog().type(WebViewDialog.NETWORK_IWLAN)
239                         TelephonyManager.NETWORK_TYPE_NR -> WebViewDialog().type(WebViewDialog.NETWORK_NR)
240                         else -> WebViewDialog().type(WebViewDialog.NETWORK_UNKNOWN)
241                     }
242
243                     // Show the alert dialog.
244                     dataNetworkDialogFragment.show(supportFragmentManager, getString(R.string.voice_network))
245                 }
246
247                 // Set the additional network info click listener.
248                 additionalNetworkInfoLinearLayout.setOnClickListener {
249                     // Instantiate the initial network info dialog fragment according to the network type.
250                     val additionalNetworkInfoDialogFragment = when (telephonyDisplayInfo.overrideNetworkType) {
251                         TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE -> WebViewDialog().type(WebViewDialog.OVERRIDE_NETWORK_NONE)
252                         TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_CA -> WebViewDialog().type(WebViewDialog.OVERRIDE_NETWORK_LTE_CA)
253                         TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_ADVANCED_PRO -> WebViewDialog().type(WebViewDialog.OVERRIDE_NETWORK_LTE_ADVANCED_PRO)
254                         TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA -> WebViewDialog().type(WebViewDialog.OVERRIDE_NETWORK_NR_NSA)
255                         TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA_MMWAVE -> WebViewDialog().type(WebViewDialog.OVERRIDE_NETWORK_NR_NSA_MMWAVE)  // Can be removed once the minimum API >= 31.
256                         TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED -> WebViewDialog().type(WebViewDialog.OVERRIDE_NETWORK_NR_ADVANCED)
257                         else -> WebViewDialog().type(WebViewDialog.OVERRIDE_NETWORK_NONE)
258                     }
259
260                     // Show the alert dialog.
261                     additionalNetworkInfoDialogFragment.show(supportFragmentManager, getString(R.string.voice_network))
262                 }
263             }
264
265             @Deprecated("Deprecated in Java")
266             override fun onServiceStateChanged(serviceState: ServiceState) {
267                 // 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).
268                 val networkRegistrationInfo = serviceState.networkRegistrationInfoList[1]
269
270                 // Get the voice network type.
271                 val voiceNetworkType = getNetworkType(networkRegistrationInfo.accessNetworkTechnology)
272
273                 // Populate the voice network text views.
274                 voiceNetworkTextView.text = getString(R.string.voice_network, voiceNetworkType[0])
275                 voiceNetworkDetailsTextView.text = voiceNetworkType[1]
276
277                 // Set the voice network click listener.
278                 voiceNetworkLinearLayout.setOnClickListener {
279                     // Instantiate the voice network dialog fragment according to the network type.
280                     val voiceNetworkDialogFragment = when (networkRegistrationInfo.accessNetworkTechnology) {
281                         TelephonyManager.NETWORK_TYPE_UNKNOWN -> WebViewDialog().type(WebViewDialog.NETWORK_UNKNOWN)
282                         TelephonyManager.NETWORK_TYPE_GPRS -> WebViewDialog().type(WebViewDialog.NETWORK_GPRS)
283                         TelephonyManager.NETWORK_TYPE_EDGE -> WebViewDialog().type(WebViewDialog.NETWORK_EDGE)
284                         TelephonyManager.NETWORK_TYPE_UMTS -> WebViewDialog().type(WebViewDialog.NETWORK_UMTS)
285                         TelephonyManager.NETWORK_TYPE_CDMA -> WebViewDialog().type(WebViewDialog.NETWORK_CDMA)
286                         TelephonyManager.NETWORK_TYPE_EVDO_0 -> WebViewDialog().type(WebViewDialog.NETWORK_EVDO_0)
287                         TelephonyManager.NETWORK_TYPE_EVDO_A -> WebViewDialog().type(WebViewDialog.NETWORK_EVDO_A)
288                         TelephonyManager.NETWORK_TYPE_1xRTT -> WebViewDialog().type(WebViewDialog.NETWORK_1xRTT)
289                         TelephonyManager.NETWORK_TYPE_HSDPA -> WebViewDialog().type(WebViewDialog.NETWORK_HSDPA)
290                         TelephonyManager.NETWORK_TYPE_HSUPA -> WebViewDialog().type(WebViewDialog.NETWORK_HSUPA)
291                         TelephonyManager.NETWORK_TYPE_HSPA -> WebViewDialog().type(WebViewDialog.NETWORK_HSPA)
292                         TelephonyManager.NETWORK_TYPE_IDEN -> WebViewDialog().type(WebViewDialog.NETWORK_IDEN)
293                         TelephonyManager.NETWORK_TYPE_EVDO_B -> WebViewDialog().type(WebViewDialog.NETWORK_EVDO_B)
294                         TelephonyManager.NETWORK_TYPE_LTE -> WebViewDialog().type(WebViewDialog.NETWORK_LTE)
295                         TelephonyManager.NETWORK_TYPE_EHRPD -> WebViewDialog().type(WebViewDialog.NETWORK_EHRPD)
296                         TelephonyManager.NETWORK_TYPE_HSPAP -> WebViewDialog().type(WebViewDialog.NETWORK_HSPAP)
297                         TelephonyManager.NETWORK_TYPE_GSM -> WebViewDialog().type(WebViewDialog.NETWORK_GSM)
298                         TelephonyManager.NETWORK_TYPE_TD_SCDMA -> WebViewDialog().type(WebViewDialog.NETWORK_TD_SCDMA)
299                         TelephonyManager.NETWORK_TYPE_IWLAN -> WebViewDialog().type(WebViewDialog.NETWORK_IWLAN)
300                         TelephonyManager.NETWORK_TYPE_NR -> WebViewDialog().type(WebViewDialog.NETWORK_NR)
301                         else -> WebViewDialog().type(WebViewDialog.NETWORK_UNKNOWN)
302                     }
303
304                     // Show the alert dialog.
305                     voiceNetworkDialogFragment.show(supportFragmentManager, getString(R.string.voice_network))
306                 }
307             }
308         }
309
310         // Start the realtime monitoring service if it is enabled.
311         if (realtimeMonitoring) {
312             // Get a handle for the activity manager.
313             val activityManager: ActivityManager = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
314
315             // 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.
316             val runningServiceInfoList: List<ActivityManager.RunningServiceInfo> = activityManager.getRunningServices(1)
317
318             // Start the service if it is not already running.
319             if (runningServiceInfoList.isEmpty()) {
320                 startService(Intent(this, RealtimeMonitoringService::class.java))
321             }
322         }
323     }
324
325     override fun onPostCreate(savedInstanceState: Bundle?) {
326         // Run the default commands.
327         super.onPostCreate(savedInstanceState)
328
329         // Sync the state of the DrawerToggle after the default `onRestoreInstanceState()` has finished.  This creates the navigation drawer icon.
330         actionBarDrawerToggle.syncState()
331     }
332
333     override fun onStart() {
334         // Run the default commands.
335         super.onStart()
336
337         // 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.
338         if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED) {  // The storage permission has been granted.
339             // Register the telephony manager listener.
340             registerTelephonyManagerListener()
341         } else {  // The phone permission has not been granted.
342             // Check if the user has previously denied the storage permission.
343             if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.READ_PHONE_STATE)) {  // Show a dialog explaining the request first.
344                 // Check to see if a phone permission dialog is already displayed.  This happens if the app is restarted when the dialog is shown.
345                 if (supportFragmentManager.findFragmentByTag(getString(R.string.phone_permission)) == null) {  // No dialog is currently shown.
346                     // Instantiate the phone permission dialog fragment.
347                     val phonePermissionDialogFragment = PhonePermissionDialog()
348
349                     // Show the phone permission alert dialog.  The permission will be requested when the dialog is closed.
350                     phonePermissionDialogFragment.show(supportFragmentManager, getString(R.string.phone_permission))
351                 }
352             } else {  // Show the permission request directly.
353                 // Request the read phone state permission.  There is only one permission request in the app, so it has a request code of 0.
354                 ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.READ_PHONE_STATE), 0)
355             }
356         }
357     }
358
359     override fun onStop() {
360         // Run the default commands.
361         super.onStop()
362
363         // Get a handle for the telephony manager.
364         val telephonyManager = getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
365
366         // Unregister the telephony manager listener.  The `PhoneStateListener` can be replaced by `TelephonyCallback` once the minimum API >= 31.
367         telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_NONE)
368     }
369
370     override fun onNavigationItemSelected(menuItem: MenuItem) : Boolean {
371         // Run the commands that correspond to the selected menu item.
372         when (menuItem.itemId) {
373             R.id.settings -> {  // Settings.
374                 // Create an intent to load the Settings activity.
375                 val settingsIntent = Intent(this, SettingsActivity::class.java)
376
377                 // Make it so.
378                 startActivity(settingsIntent)
379             }
380
381             R.id.protocols -> {
382                 // Create an intent to load the Protocols activity.
383                 val protocolsIntent = Intent(this, ProtocolsActivity::class.java)
384
385                 // Make it so.
386                 startActivity(protocolsIntent)
387             }
388
389             R.id.logcat -> {  // Logcat.
390                 // Create an intent to load the Logcat activity.
391                 val logcatIntent = Intent(this, LogcatActivity::class.java)
392
393                 // Make it so.
394                 startActivity(logcatIntent)
395             }
396
397             R.id.permissions -> {  // Permissions.
398                 // Instantiate the permissions dialog fragment.
399                 val permissionsDialogFragment = WebViewDialog().type(WebViewDialog.PERMISSIONS)
400
401                 // Show the alert dialog.
402                 permissionsDialogFragment.show(supportFragmentManager, getString(R.string.permissions))
403             }
404
405             R.id.privacy_policy -> {  // Privacy Policy.
406                 // Instantiate the privacy policy dialog fragment.
407                 val privacyPolicyDialogFragment = WebViewDialog().type(WebViewDialog.PRIVACY_POLICY)
408
409                 // Show the alert dialog.
410                 privacyPolicyDialogFragment.show(supportFragmentManager, getString(R.string.privacy_policy))
411             }
412
413             R.id.changelog -> {  // Changelog.
414                 // Instantiate the changelog dialog fragment.
415                 val changelogDialogFragment = WebViewDialog().type(WebViewDialog.CHANGELOG)
416
417                 // Show the alert dialog.
418                 changelogDialogFragment.show(supportFragmentManager, getString(R.string.changelog))
419             }
420
421             R.id.licenses -> {  // Licenses.
422                 // Instantiate the licenses dialog fragment.
423                 val licensesDialogFragment = WebViewDialog().type(WebViewDialog.LICENSES)
424
425                 // Show the alert dialog.
426                 licensesDialogFragment.show(supportFragmentManager, getString(R.string.licenses))
427             }
428
429             R.id.contributors -> {  // Contributors.
430                 // Instantiate the contributors dialog fragment.
431                 val contributorsDialogFragment = WebViewDialog().type(WebViewDialog.CONTRIBUTORS)
432
433                 // Show the alert dialog.
434                 contributorsDialogFragment.show(supportFragmentManager, getString(R.string.contributors))
435             }
436
437             R.id.news -> {  // News.
438                 // Create a news URL intent.
439                 val newsUrlIntent = Intent(Intent.ACTION_VIEW)
440
441                 // Add the URL to the intent.
442                 newsUrlIntent.data = Uri.parse("https://www.stoutner.com/category/privacy-cell/")
443
444                 // Make it so.
445                 startActivity(newsUrlIntent)
446             }
447
448             R.id.roadmap -> {  // Roadmap.
449                 // Create a roadmap URL intent.
450                 val roadmapUrlIntent = Intent(Intent.ACTION_VIEW)
451
452                 // Add the URL to the intent.
453                 roadmapUrlIntent.data = Uri.parse("https://www.stoutner.com/category/privacy-cell-roadmap/")
454
455                 // Make it so.
456                 startActivity(roadmapUrlIntent)
457             }
458
459             R.id.bug_tracker -> {  // Bug tracker.
460                 // Create a bug tracker URL intent.
461                 val bugTrackerUrlIntent = Intent(Intent.ACTION_VIEW)
462
463                 // Add the URL to the intent.
464                 bugTrackerUrlIntent.data = Uri.parse("https://redmine.stoutner.com/projects/privacy-cell/issues")
465
466                 // Make it so.
467                 startActivity(bugTrackerUrlIntent)
468             }
469
470             R.id.forum -> {  // Forum.
471                 // Create a forum URL intent.
472                 val forumUrlIntent = Intent(Intent.ACTION_VIEW)
473
474                 // Add the URL to the intent.
475                 forumUrlIntent.data = Uri.parse("https://redmine.stoutner.com/projects/privacy-cell/boards")
476
477                 // Make it so.
478                 startActivity(forumUrlIntent)
479             }
480
481             R.id.donations -> {  // Donations.
482                 // Create a donations URL intent.
483                 val donationsUrlIntent = Intent(Intent.ACTION_VIEW)
484
485                 // Add the URL to the intent.
486                 donationsUrlIntent.data = Uri.parse("https://www.stoutner.com/donations/")
487
488                 // Make it so.
489                 startActivity(donationsUrlIntent)
490             }
491         }
492
493         // Close the navigation drawer.
494         drawerLayout.closeDrawer(GravityCompat.START)
495
496         // Consume the click.
497         return true
498     }
499
500     override fun onCloseStoragePermissionDialog() {
501         // Request the read phone state permission.  There is only one permission request in the app, so it has a request code of 0.
502         ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.READ_PHONE_STATE), 0)
503     }
504
505     override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
506         // Run the default commands.
507         super.onRequestPermissionsResult(requestCode, permissions, grantResults)
508
509         //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).
510         if (grantResults.isNotEmpty()) {
511             // Check to see if the read phone state permission was granted.  If the dialog was canceled the grant results will be empty.
512             if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {  // The read phone state permission was granted.
513                 // Populate Privacy Cell.
514                 registerTelephonyManagerListener()
515             } else {  // The read phone state permission was denied.
516                 // Display the phone permission text on the main activity.
517                 summaryTextView.text = getString(R.string.phone_permission_text)
518             }
519         }
520     }
521
522     private fun registerTelephonyManagerListener() {
523         // Get a handle for the telephony manager.
524         val telephonyManager = getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
525
526         // Listen to changes in the cell network state.  The `PhoneStateListener` can be replaced by `TelephonyCallback` once the minimum API >= 31.
527         telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_DISPLAY_INFO_CHANGED or PhoneStateListener.LISTEN_SERVICE_STATE)
528     }
529
530     private fun getNetworkType(networkType: Int) : Array<String> {
531         // Return the string that corresponds to the network type.
532         return when(networkType) {
533             TelephonyManager.NETWORK_TYPE_UNKNOWN -> arrayOf(getString(R.string.unknown), "")
534             TelephonyManager.NETWORK_TYPE_GPRS -> arrayOf(getString(R.string.gprs), getString(R.string.gprs_detail))
535             TelephonyManager.NETWORK_TYPE_EDGE -> arrayOf(getString(R.string.edge), getString(R.string.edge_detail))
536             TelephonyManager.NETWORK_TYPE_UMTS -> arrayOf(getString(R.string.umts), getString(R.string.umts_detail))
537             TelephonyManager.NETWORK_TYPE_CDMA -> arrayOf(getString(R.string.cdma), getString(R.string.cdma_detail))
538             TelephonyManager.NETWORK_TYPE_EVDO_0 -> arrayOf(getString(R.string.evdo_0), getString(R.string.evdo_0_detail))
539             TelephonyManager.NETWORK_TYPE_EVDO_A -> arrayOf(getString(R.string.evdo_a), getString(R.string.evdo_a_detail))
540             TelephonyManager.NETWORK_TYPE_1xRTT -> arrayOf(getString(R.string.rtt), getString(R.string.rtt_detail))
541             TelephonyManager.NETWORK_TYPE_HSDPA -> arrayOf(getString(R.string.hsdpa), getString(R.string.hsdpa_detail))
542             TelephonyManager.NETWORK_TYPE_HSUPA -> arrayOf(getString(R.string.hsupa), getString(R.string.hsupa_detail))
543             TelephonyManager.NETWORK_TYPE_HSPA -> arrayOf(getString(R.string.hspa), getString(R.string.hspa_detail))
544             TelephonyManager.NETWORK_TYPE_IDEN -> arrayOf(getString(R.string.iden), getString(R.string.iden_detail))
545             TelephonyManager.NETWORK_TYPE_EVDO_B -> arrayOf(getString(R.string.evdo_b), getString(R.string.evdo_b_detail))
546             TelephonyManager.NETWORK_TYPE_LTE -> arrayOf(getString(R.string.lte), getString(R.string.lte_detail))
547             TelephonyManager.NETWORK_TYPE_EHRPD -> arrayOf(getString(R.string.ehrpd), getString(R.string.ehrpd_detail))
548             TelephonyManager.NETWORK_TYPE_HSPAP -> arrayOf(getString(R.string.hspap), getString(R.string.hspap_detail))
549             TelephonyManager.NETWORK_TYPE_GSM -> arrayOf(getString(R.string.gsm), getString(R.string.gsm_detail))
550             TelephonyManager.NETWORK_TYPE_TD_SCDMA -> arrayOf(getString(R.string.td_scdma), getString(R.string.td_scdma_detail))
551             TelephonyManager.NETWORK_TYPE_IWLAN -> arrayOf(getString(R.string.iwlan), getString(R.string.iwlan_detail))
552             TelephonyManager.NETWORK_TYPE_NR -> arrayOf(getString(R.string.nr), getString(R.string.nr_detail))
553             else -> arrayOf(getString(R.string.error), "")
554         }
555     }
556
557     private fun getAdditionalNetworkInfo(overrideNetworkType: Int) : Array<String> {
558         // Return the string that corresponds to the override network type.
559         return when(overrideNetworkType) {
560             TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE -> arrayOf(getString(R.string.none), "")
561             TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_CA -> arrayOf(getString(R.string.lte_ca), getString(R.string.lte_ca_detail))
562             TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_ADVANCED_PRO -> arrayOf(getString(R.string.lte_advanced_pro), getString(R.string.lte_advanced_pro_detail))
563             TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA -> arrayOf(getString(R.string.nr_nsa), getString(R.string.nr_nsa_detail))
564             TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA_MMWAVE -> arrayOf(getString(R.string.nr_nsa_mmwave), getString(R.string.nr_nsa_mmwave_detail))  // Can be removed once the minimum API >= 31.
565             TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED -> arrayOf(getString(R.string.nr_advanced), getString(R.string.nr_advanced_detail))
566             else -> arrayOf(getString(R.string.error), "")
567         }
568     }
569 }