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
78 override fun onResume() {
79 // Run the default commands.
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.
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()
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))
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)
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)
109 override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
110 // Run the default commands.
111 super.onRequestPermissionsResult(requestCode, permissions, grantResults)
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)
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))
136 secureFromStingrayTextView.text = getString(R.string.secure_from_stingray)
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))
145 secureFromStingrayTextView.text = getString(R.string.not_secure_from_stingray)
147 // Set the text color.
148 secureFromStingrayTextView.setTextColor(getColor(R.color.red_text))
150 // Get the strings that correspond to the network information.
151 val dataNetworkType = getNetworkType(telephonyDisplayInfo.networkType)
152 val additionalNetworkInfo = getAdditionalNetworkInfo(telephonyDisplayInfo.overrideNetworkType)
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]
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]
166 // Get the voice network type.
167 val voiceNetworkType = getNetworkType(networkRegistrationInfo.accessNetworkTechnology)
169 // Populate the voice network text views.
170 voiceNetworkTextView.text = getString(R.string.voice_network, voiceNetworkType[0])
171 voiceNetworkDetailsTextView.text = voiceNetworkType[1]
173 }, PhoneStateListener.LISTEN_DISPLAY_INFO_CHANGED or PhoneStateListener.LISTEN_SERVICE_STATE)
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), "")
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), "")