Reregister the listener on every resume.
[PrivacyCell.git] / app / src / main / java / com / stoutner / privacycell / activities / PrivacyCell.kt
1 /*
2  * Copyright © 2021 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 Browser.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 package com.stoutner.privacycell.activities
21
22 import android.Manifest
23 import android.content.Context
24 import android.content.pm.PackageManager
25 import android.os.Bundle
26 import android.telephony.PhoneStateListener
27 import android.telephony.ServiceState
28 import android.telephony.TelephonyDisplayInfo
29 import android.telephony.TelephonyManager
30 import android.widget.ImageView
31 import android.widget.TextView
32
33 import androidx.appcompat.app.AppCompatActivity
34 import androidx.appcompat.content.res.AppCompatResources
35 import androidx.core.app.ActivityCompat
36 import androidx.fragment.app.DialogFragment
37
38 import com.stoutner.privacycell.R
39 import com.stoutner.privacycell.dialogs.PhonePermissionDialog
40
41 class PrivacyCell : AppCompatActivity(), PhonePermissionDialog.StoragePermissionDialogListener {
42     // Declare the class variables.
43     private lateinit var context: Context
44     private lateinit var telephonyManager: TelephonyManager
45
46     // Declare the views.
47     lateinit var secureFromStingrayImageView: ImageView
48     lateinit var secureFromStingrayTextView: TextView
49     lateinit var voiceNetworkTextView: TextView
50     lateinit var voiceNetworkDetailsTextView: TextView
51     lateinit var dataNetworkTextView: TextView
52     lateinit var dataNetworkDetailsTextView: TextView
53     lateinit var additionalNetworkInfoTextView: TextView
54     lateinit var additionalNetworkInfoDetailsTextView: TextView
55
56     override fun onCreate(savedInstanceState: Bundle?) {
57         // Run the default commands.
58         super.onCreate(savedInstanceState)
59
60         // Set the content view.
61         setContentView(R.layout.privacy_cell_scrollview)
62
63         // Get handles for the views.
64         secureFromStingrayImageView = findViewById(R.id.secure_from_stingray_imageview)
65         secureFromStingrayTextView = findViewById(R.id.secure_from_stingray_textview)
66         voiceNetworkTextView = findViewById(R.id.voice_network)
67         voiceNetworkDetailsTextView = findViewById(R.id.voice_network_details)
68         dataNetworkTextView = findViewById(R.id.data_network)
69         dataNetworkDetailsTextView = findViewById(R.id.data_network_details)
70         additionalNetworkInfoTextView = findViewById(R.id.additional_network_info)
71         additionalNetworkInfoDetailsTextView = findViewById(R.id.additional_network_info_details)
72
73         // Get handles for the context and the telephony manager.
74         context = this
75         telephonyManager = getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
76     }
77
78     override fun onResume() {
79         // Run the default commands.
80         super.onResume()
81
82         // 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.
83         if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED) {  // The storage permission has been granted.
84             // Populate Privacy Cell.
85             populatePrivacyCell()
86         } else {  // The phone permission has not been granted.
87             // Check if the user has previously denied the storage permission.
88             if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.READ_PHONE_STATE)) {  // Show a dialog explaining the request first.
89                 // Check to see if a phone permission dialog is already displayed.  This happens if the app is restarted when the dialog is shown.
90                 if (supportFragmentManager.findFragmentByTag(getString(R.string.phone_permission)) == null) {  // No dialog is currently shown.
91                     // Instantiate the phone permission dialog fragment.
92                     val phonePermissionDialogFragment: DialogFragment = PhonePermissionDialog()
93
94                     // Show the phone permission alert dialog.  The permission will be requested when the dialog is closed.
95                     phonePermissionDialogFragment.show(supportFragmentManager, getString(R.string.phone_permission))
96                 }
97             } else {  // Show the permission request directly.
98                 // Request the read phone state permission.  There is only one permission request in the app, so it has a request code of 0.
99                 ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.READ_PHONE_STATE), 0)
100             }
101         }
102     }
103
104     override fun onCloseStoragePermissionDialog() {
105         // Request the read phone state permission.  There is only one permission request in the app, so it has a request code of 0.
106         ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.READ_PHONE_STATE), 0)
107     }
108
109     override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
110         // Run the default commands.
111         super.onRequestPermissionsResult(requestCode, permissions, grantResults)
112
113         //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).
114         if (grantResults.isNotEmpty()) {
115             // Check to see if the read phone state permission was granted.  If the dialog was canceled the grant results will be empty.
116             if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {  // The read phone state permission was granted.
117                 // Populate Privacy Cell.
118                 populatePrivacyCell()
119             } else {  // The read phone state permission was denied.
120                 // Display the phone permission text on the main activity.
121                 secureFromStingrayTextView.text = getString(R.string.phone_permission_text)
122             }
123         }
124     }
125
126     private fun populatePrivacyCell() {
127         // Listen to changes in the cell network state.
128         telephonyManager.listen(object : PhoneStateListener() {
129             override fun onDisplayInfoChanged(telephonyDisplayInfo: TelephonyDisplayInfo) {
130                 // Populate the stingray security information.  <https://source.android.com/devices/tech/connect/acts-5g-testing>
131                 if (telephonyDisplayInfo.networkType == TelephonyManager.NETWORK_TYPE_NR) {  // This is a secure 5G NR SA network.
132                     // Populate the image view.
133                     secureFromStingrayImageView.setImageDrawable(AppCompatResources.getDrawable(context, R.drawable.secure_5g_nr_sa))
134
135                     // Set the text.
136                     secureFromStingrayTextView.text = getString(R.string.secure_from_stingray)
137
138                     // Set the text color.
139                     secureFromStingrayTextView.setTextColor(getColor(R.color.blue_text))
140                 } else {  // This is not a secure 5G NR SA network.
141                     // Populate the image view.
142                     secureFromStingrayImageView.setImageDrawable(AppCompatResources.getDrawable(context, R.drawable.not_secure))
143
144                     // Set the text.
145                     secureFromStingrayTextView.text = getString(R.string.not_secure_from_stingray)
146
147                     // Set the text color.
148                     secureFromStingrayTextView.setTextColor(getColor(R.color.red_text))
149
150                     // Get the strings that correspond to the network information.
151                     val dataNetworkType = getNetworkType(telephonyDisplayInfo.networkType)
152                     val additionalNetworkInfo = getAdditionalNetworkInfo(telephonyDisplayInfo.overrideNetworkType)
153
154                     // Populate the data network text views.
155                     dataNetworkTextView.text = getString(R.string.data_network, dataNetworkType[0])
156                     dataNetworkDetailsTextView.text = dataNetworkType[1]
157                     additionalNetworkInfoTextView.text = getString(R.string.additional_network_info, additionalNetworkInfo[0])
158                     additionalNetworkInfoDetailsTextView.text = additionalNetworkInfo[1]
159                 }
160             }
161
162             override fun onServiceStateChanged(serviceState: ServiceState) {
163                 // 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).
164                 val networkRegistrationInfo = serviceState.networkRegistrationInfoList[1]
165
166                 // Get the voice network type.
167                 val voiceNetworkType = getNetworkType(networkRegistrationInfo.accessNetworkTechnology)
168
169                 // Populate the voice network text views.
170                 voiceNetworkTextView.text = getString(R.string.voice_network, voiceNetworkType[0])
171                 voiceNetworkDetailsTextView.text = voiceNetworkType[1]
172             }
173         }, PhoneStateListener.LISTEN_DISPLAY_INFO_CHANGED or PhoneStateListener.LISTEN_SERVICE_STATE)
174     }
175
176     private fun getNetworkType(networkType: Int) : Array<String> {
177         // Return the string that corresponds to the network type.
178         return when(networkType) {
179             TelephonyManager.NETWORK_TYPE_UNKNOWN -> arrayOf(getString(R.string.unknown), "")
180             TelephonyManager.NETWORK_TYPE_GPRS -> arrayOf(getString(R.string.gprs), getString(R.string.gprs_detal))
181             TelephonyManager.NETWORK_TYPE_EDGE -> arrayOf(getString(R.string.edge), getString(R.string.edge_detail))
182             TelephonyManager.NETWORK_TYPE_UMTS -> arrayOf(getString(R.string.umts), getString(R.string.umts_detail))
183             TelephonyManager.NETWORK_TYPE_CDMA -> arrayOf(getString(R.string.cdma), getString(R.string.cdma_detail))
184             TelephonyManager.NETWORK_TYPE_EVDO_0 -> arrayOf(getString(R.string.evdo_0), getString(R.string.evdo_0_detail))
185             TelephonyManager.NETWORK_TYPE_EVDO_A -> arrayOf(getString(R.string.evdo_a), getString(R.string.evdo_a_detail))
186             TelephonyManager.NETWORK_TYPE_1xRTT -> arrayOf(getString(R.string.rtt), getString(R.string.rtt_detail))
187             TelephonyManager.NETWORK_TYPE_HSDPA -> arrayOf(getString(R.string.hsdpa), getString(R.string.hsdpa_detail))
188             TelephonyManager.NETWORK_TYPE_HSUPA -> arrayOf(getString(R.string.hsupa), getString(R.string.hsupa_detail))
189             TelephonyManager.NETWORK_TYPE_HSPA -> arrayOf(getString(R.string.hspa), getString(R.string.hspa_detail))
190             TelephonyManager.NETWORK_TYPE_IDEN -> arrayOf(getString(R.string.iden), getString(R.string.iden_detail))
191             TelephonyManager.NETWORK_TYPE_EVDO_B -> arrayOf(getString(R.string.evdo_b), getString(R.string.evdo_b_detail))
192             TelephonyManager.NETWORK_TYPE_LTE -> arrayOf(getString(R.string.lte), getString(R.string.lte_detail))
193             TelephonyManager.NETWORK_TYPE_EHRPD -> arrayOf(getString(R.string.ehrpd), getString(R.string.ehrpd_detail))
194             TelephonyManager.NETWORK_TYPE_HSPAP -> arrayOf(getString(R.string.hspap), getString(R.string.hspap_detail))
195             TelephonyManager.NETWORK_TYPE_GSM -> arrayOf(getString(R.string.gsm), getString(R.string.gsm_detail))
196             TelephonyManager.NETWORK_TYPE_TD_SCDMA -> arrayOf(getString(R.string.td_scdma), getString(R.string.td_scdma_detail))
197             TelephonyManager.NETWORK_TYPE_IWLAN -> arrayOf(getString(R.string.iwlan), getString(R.string.iwlan_detail))
198             TelephonyManager.NETWORK_TYPE_NR -> arrayOf(getString(R.string.nr), getString(R.string.nr_detail))
199             else -> arrayOf(getString(R.string.error), "")
200         }
201     }
202
203     private fun getAdditionalNetworkInfo(overrideNetworkType: Int) : Array<String> {
204         // Return the string that corresponds to the override network type.
205         return when(overrideNetworkType) {
206             TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE -> arrayOf(getString(R.string.none), "")
207             TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_CA -> arrayOf(getString(R.string.lte_ca), getString(R.string.lte_ca_detail))
208             TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_ADVANCED_PRO -> arrayOf(getString(R.string.lte_advanced_pro), getString(R.string.lte_advanced_pro_detail))
209             TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA -> arrayOf(getString(R.string.lte_nr_nsa), getString(R.string.lte_nr_nsa_detail))
210             TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA_MMWAVE -> arrayOf(getString(R.string.lte_nr_nsa_mmwave), getString(R.string.lte_nr_nsa_mmwave_detail))
211             else -> arrayOf(getString(R.string.error), "")
212         }
213     }
214 }