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 Browser. If not, see <http://www.gnu.org/licenses/>.
20 package com.stoutner.privacycell.activities
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
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
38 import com.stoutner.privacycell.R
39 import com.stoutner.privacycell.dialogs.PhonePermissionDialog
41 class PrivacyCell : AppCompatActivity(), PhonePermissionDialog.StoragePermissionDialogListener {
42 // Declare the class variables.
43 private lateinit var context: Context
44 private lateinit var telephonyManager: TelephonyManager
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
56 override fun onCreate(savedInstanceState: Bundle?) {
57 // Run the default commands.
58 super.onCreate(savedInstanceState)
60 // Set the content view.
61 setContentView(R.layout.privacy_cell_scrollview)
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)
73 // Get handles for the context and the telephony manager.
75 telephonyManager = getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
77 // Check to see if the read phone state permission has been granted.
78 if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED) { // The storage permission has been granted.
79 // Populate Privacy Cell.
81 } else { // The phone permission has not been granted.
82 // Check if the user has previously denied the storage permission.
83 if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.READ_PHONE_STATE)) { // Show a dialog explaining the request first.
84 // Check to see if a phone permission dialog is already displayed. This happens if the app is restarted when the dialog is shown.
85 if (supportFragmentManager.findFragmentByTag(getString(R.string.phone_permission)) == null) { // No dialog is currently shown.
86 // Instantiate the phone permission dialog fragment.
87 val phonePermissionDialogFragment: DialogFragment = PhonePermissionDialog()
89 // Show the phone permission alert dialog. The permission will be requested when the dialog is closed.
90 phonePermissionDialogFragment.show(supportFragmentManager, getString(R.string.phone_permission))
92 } else { // Show the permission request directly.
93 // Request the read phone state permission. There is only one permission request in the app, so it has a request code of 0.
94 ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.READ_PHONE_STATE), 0)
99 override fun onCloseStoragePermissionDialog() {
100 // Request the read phone state permission. There is only one permission request in the app, so it has a request code of 0.
101 ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.READ_PHONE_STATE), 0)
104 override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
105 // Run the default commands.
106 super.onRequestPermissionsResult(requestCode, permissions, grantResults)
108 //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).
109 if (grantResults.isNotEmpty()) {
110 // Check to see if the read phone state permission was granted. If the dialog was canceled the grant results will be empty.
111 if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { // The read phone state permission was granted.
112 // Populate Privacy Cell.
113 populatePrivacyCell()
114 } else { // The read phone state permission was denied.
115 // Display the phone permission text on the main activity.
116 secureFromStingrayTextView.text = getString(R.string.phone_permission_text)
121 private fun populatePrivacyCell() {
122 // Listen to changes in the cell network state.
123 telephonyManager.listen(object : PhoneStateListener() {
124 override fun onDisplayInfoChanged(telephonyDisplayInfo: TelephonyDisplayInfo) {
125 // Populate the stingray security information. <https://source.android.com/devices/tech/connect/acts-5g-testing>
126 if (telephonyDisplayInfo.networkType == TelephonyManager.NETWORK_TYPE_NR) { // This is a secure 5G NR SA network.
127 // Populate the image view.
128 secureFromStingrayImageView.setImageDrawable(AppCompatResources.getDrawable(context, R.drawable.secure_5g_nr_sa))
131 secureFromStingrayTextView.text = getString(R.string.secure_from_stingray)
133 // Set the text color.
134 secureFromStingrayTextView.setTextColor(getColor(R.color.blue_text))
135 } else { // This is not a secure 5G NR SA network.
136 // Populate the image view.
137 secureFromStingrayImageView.setImageDrawable(AppCompatResources.getDrawable(context, R.drawable.not_secure))
140 secureFromStingrayTextView.text = getString(R.string.not_secure_from_stingray)
142 // Set the text color.
143 secureFromStingrayTextView.setTextColor(getColor(R.color.red_text))
145 // Get the strings that correspond to the network information.
146 val dataNetworkType = getNetworkType(telephonyDisplayInfo.networkType)
147 val additionalNetworkInfo = getAdditionalNetworkInfo(telephonyDisplayInfo.overrideNetworkType)
149 // Populate the data network text views.
150 dataNetworkTextView.text = getString(R.string.data_network, dataNetworkType[0])
151 dataNetworkDetailsTextView.text = dataNetworkType[1]
152 additionalNetworkInfoTextView.text = getString(R.string.additional_network_info, additionalNetworkInfo[0])
153 additionalNetworkInfoDetailsTextView.text = additionalNetworkInfo[1]
157 override fun onServiceStateChanged(serviceState: ServiceState) {
158 // 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).
159 val networkRegistrationInfo = serviceState.networkRegistrationInfoList[1]
161 // Get the voice network type.
162 val voiceNetworkType = getNetworkType(networkRegistrationInfo.accessNetworkTechnology)
164 // Populate the voice network text views.
165 voiceNetworkTextView.text = getString(R.string.voice_network, voiceNetworkType[0])
166 voiceNetworkDetailsTextView.text = voiceNetworkType[1]
168 }, PhoneStateListener.LISTEN_DISPLAY_INFO_CHANGED or PhoneStateListener.LISTEN_SERVICE_STATE)
171 private fun getNetworkType(networkType: Int) : Array<String> {
172 // Return the string that corresponds to the network type.
173 return when(networkType) {
174 TelephonyManager.NETWORK_TYPE_UNKNOWN -> arrayOf(getString(R.string.unknown), "")
175 TelephonyManager.NETWORK_TYPE_GPRS -> arrayOf(getString(R.string.gprs), getString(R.string.gprs_detal))
176 TelephonyManager.NETWORK_TYPE_EDGE -> arrayOf(getString(R.string.edge), getString(R.string.edge_detail))
177 TelephonyManager.NETWORK_TYPE_UMTS -> arrayOf(getString(R.string.umts), getString(R.string.umts_detail))
178 TelephonyManager.NETWORK_TYPE_CDMA -> arrayOf(getString(R.string.cdma), getString(R.string.cdma_detail))
179 TelephonyManager.NETWORK_TYPE_EVDO_0 -> arrayOf(getString(R.string.evdo_0), getString(R.string.evdo_0_detail))
180 TelephonyManager.NETWORK_TYPE_EVDO_A -> arrayOf(getString(R.string.evdo_a), getString(R.string.evdo_a_detail))
181 TelephonyManager.NETWORK_TYPE_1xRTT -> arrayOf(getString(R.string.rtt), getString(R.string.rtt_detail))
182 TelephonyManager.NETWORK_TYPE_HSDPA -> arrayOf(getString(R.string.hsdpa), getString(R.string.hsdpa_detail))
183 TelephonyManager.NETWORK_TYPE_HSUPA -> arrayOf(getString(R.string.hsupa), getString(R.string.hsupa_detail))
184 TelephonyManager.NETWORK_TYPE_HSPA -> arrayOf(getString(R.string.hspa), getString(R.string.hspa_detail))
185 TelephonyManager.NETWORK_TYPE_IDEN -> arrayOf(getString(R.string.iden), getString(R.string.iden_detail))
186 TelephonyManager.NETWORK_TYPE_EVDO_B -> arrayOf(getString(R.string.evdo_b), getString(R.string.evdo_b_detail))
187 TelephonyManager.NETWORK_TYPE_LTE -> arrayOf(getString(R.string.lte), getString(R.string.lte_detail))
188 TelephonyManager.NETWORK_TYPE_EHRPD -> arrayOf(getString(R.string.ehrpd), getString(R.string.ehrpd_detail))
189 TelephonyManager.NETWORK_TYPE_HSPAP -> arrayOf(getString(R.string.hspap), getString(R.string.hspap_detail))
190 TelephonyManager.NETWORK_TYPE_GSM -> arrayOf(getString(R.string.gsm), getString(R.string.gsm_detail))
191 TelephonyManager.NETWORK_TYPE_TD_SCDMA -> arrayOf(getString(R.string.td_scdma), getString(R.string.td_scdma_detail))
192 TelephonyManager.NETWORK_TYPE_IWLAN -> arrayOf(getString(R.string.iwlan), getString(R.string.iwlan_detail))
193 TelephonyManager.NETWORK_TYPE_NR -> arrayOf(getString(R.string.nr), getString(R.string.nr_detail))
194 else -> arrayOf(getString(R.string.error), "")
198 private fun getAdditionalNetworkInfo(overrideNetworkType: Int) : Array<String> {
199 // Return the string that corresponds to the override network type.
200 return when(overrideNetworkType) {
201 TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE -> arrayOf(getString(R.string.none), "")
202 TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_CA -> arrayOf(getString(R.string.lte_ca), getString(R.string.lte_ca_detail))
203 TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_ADVANCED_PRO -> arrayOf(getString(R.string.lte_advanced_pro), getString(R.string.lte_advanced_pro_detail))
204 TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA -> arrayOf(getString(R.string.lte_nr_nsa), getString(R.string.lte_nr_nsa_detail))
205 TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA_MMWAVE -> arrayOf(getString(R.string.lte_nr_nsa_mmwave), getString(R.string.lte_nr_nsa_mmwave_detail))
206 else -> arrayOf(getString(R.string.error), "")