/*
- * Copyright © 2021-2022 Soren Stoutner <soren@stoutner.com>.
+ * Copyright 2021-2022 Soren Stoutner <soren@stoutner.com>.
*
* This file is part of Privacy Cell <https://www.stoutner.com/privacy-cell>.
*
import android.os.Binder
import android.os.IBinder
import android.telephony.PhoneStateListener // This can be replaced by `TelephonyCallback` once the minimum API >= 31.
+import android.telephony.ServiceState
import android.telephony.TelephonyDisplayInfo
import android.telephony.TelephonyManager
import com.stoutner.privacycell.R
import com.stoutner.privacycell.activities.PrivacyCellActivity
+import com.stoutner.privacycell.helpers.ProtocolHelper
import com.stoutner.privacycell.workers.RegisterRealtimeListenerWorker
import java.util.concurrent.TimeUnit
// Define the class variables.
private var currentStatus = ""
+ private var voiceNetworkSecurityStatus = ProtocolHelper.UNPOPULATED
+ private var dataNetworkSecurityStatus = ProtocolHelper.UNPOPULATED
+
+ // Declare the class variables.
+ private lateinit var notificationManager: NotificationManager
private lateinit var phoneStateListener: PhoneStateListener // The `PhoneStateListener` can be replaced by `TelephonyCallback` once the minimum API >= 31.
+ private lateinit var privacyCellPendingIntent: PendingIntent
inner class ServiceBinder : Binder() {
// Get a copy of this service as a binder.
// So, the default value is set to true, which is the safest value if the shared preferences can't be queried.
if (sharedPreferences.getBoolean(applicationContext.getString(R.string.realtime_monitoring_key), true)) { // Realtime monitoring is enabled.
// Get a handle for the notification manager.
- val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
+ notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
// Create a notification channel group.
notificationManager.createNotificationChannelGroup(NotificationChannelGroup(REALTIME_MONITORING, getString(R.string.realtime_monitoring)))
val privacyCellIntent = Intent(this, PrivacyCellActivity::class.java)
// Create a pending intent from the Privacy Cell intent.
- val privacyCellPendingIntent = PendingIntent.getActivity(this, 0, privacyCellIntent, PendingIntent.FLAG_IMMUTABLE)
+ privacyCellPendingIntent = PendingIntent.getActivity(this, 0, privacyCellIntent, PendingIntent.FLAG_IMMUTABLE)
// Set the notification to open Privacy Cell.
notificationBuilder.setContentIntent(privacyCellPendingIntent)
// Set the color.
notificationBuilder.setColor(getColor(R.color.red_notification_icon))
+ // Prevent swiping to dismiss the notification. This no longer works (except on the lock screen) in API >= 34.
+ notificationBuilder.setOngoing(true)
+
// Start the foreground notification.
startForeground(NOTIFICATION_ID, notificationBuilder.build())
+ // Instantiate the protocol helper.
+ val protocolHelper = ProtocolHelper()
+
+ // Get a handle for the telephony manager.
+ val telephonyManager = getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
+
// Define the phone state listener. The `PhoneStateListener` can be replaced by `TelephonyCallback` once the minimum API >= 31.
phoneStateListener = object : PhoneStateListener() {
@Deprecated("Deprecated in Java")
- override fun onDisplayInfoChanged(telephonyDisplayInfo: TelephonyDisplayInfo) {
- // Get the consider 3G antiquated preference.
- val consider3gAntiquated = sharedPreferences.getBoolean(getString(R.string.consider_3g_antiquated_key), false)
-
- // Populate the notification according to the network type.
- if ((telephonyDisplayInfo.networkType == TelephonyManager.NETWORK_TYPE_NR) || (telephonyDisplayInfo.networkType == TelephonyManager.NETWORK_TYPE_IWLAN) ||
- (telephonyDisplayInfo.networkType == TelephonyManager.NETWORK_TYPE_UNKNOWN)) { // This is a secure network.
- // Only update the notification if the network status has changed.
- if (currentStatus != SECURE_NETWORK) {
- // Create a secure network notification builder.
- val secureNetworkNotificationBuilder = Notification.Builder(applicationContext, SECURE_NETWORK)
-
- // Set the notification to open Privacy Cell.
- secureNetworkNotificationBuilder.setContentIntent(privacyCellPendingIntent)
-
- // Set the notification text.
- secureNetworkNotificationBuilder.setContentText(getString(R.string.secure_network))
-
- // Set the notification icon.
- secureNetworkNotificationBuilder.setSmallIcon(R.drawable.secure_notification_enabled)
-
- // Set the color.
- secureNetworkNotificationBuilder.setColor(getColor(R.color.blue_icon))
-
- // Update the notification.
- notificationManager.notify(NOTIFICATION_ID, secureNetworkNotificationBuilder.build())
-
- // Store the new network status.
- currentStatus = SECURE_NETWORK
- }
- } else if ((telephonyDisplayInfo.networkType == TelephonyManager.NETWORK_TYPE_LTE) || (!consider3gAntiquated && (telephonyDisplayInfo.networkType == TelephonyManager.NETWORK_TYPE_1xRTT ||
- (telephonyDisplayInfo.networkType == TelephonyManager.NETWORK_TYPE_EVDO_0) || (telephonyDisplayInfo.networkType == TelephonyManager.NETWORK_TYPE_EVDO_A) ||
- (telephonyDisplayInfo.networkType == TelephonyManager.NETWORK_TYPE_EVDO_B) || (telephonyDisplayInfo.networkType == TelephonyManager.NETWORK_TYPE_EHRPD) ||
- (telephonyDisplayInfo.networkType == TelephonyManager.NETWORK_TYPE_UMTS) || (telephonyDisplayInfo.networkType == TelephonyManager.NETWORK_TYPE_TD_SCDMA) ||
- (telephonyDisplayInfo.networkType == TelephonyManager.NETWORK_TYPE_HSDPA) || (telephonyDisplayInfo.networkType == TelephonyManager.NETWORK_TYPE_HSUPA) ||
- (telephonyDisplayInfo.networkType == TelephonyManager.NETWORK_TYPE_HSPA) || (telephonyDisplayInfo.networkType == TelephonyManager.NETWORK_TYPE_HSPAP)))) {
- // This is an insecure network.
- // Only update the notification if the network status has changed.
- if (currentStatus != INSECURE_NETWORK) {
- // Create an insecure network notification builder.
- val insecureNetworkNotificationBuilder = Notification.Builder(applicationContext, INSECURE_NETWORK)
-
- // Set the notification to open Privacy Cell.
- insecureNetworkNotificationBuilder.setContentIntent(privacyCellPendingIntent)
-
- // Set the notification text.
- insecureNetworkNotificationBuilder.setContentText(getString(R.string.insecure_network))
-
- // Set the notification icon.
- insecureNetworkNotificationBuilder.setSmallIcon(R.drawable.insecure_notification_enabled)
-
- // Set the color.
- insecureNetworkNotificationBuilder.setColor(getColor(R.color.yellow_notification_icon))
-
- // Update the notification.
- notificationManager.notify(NOTIFICATION_ID, insecureNetworkNotificationBuilder.build())
-
- // Store the new network status.
- currentStatus = INSECURE_NETWORK
- }
- } else { // This is an antiquated network.
- // Only update the notification if the network status has changed.
- if (currentStatus != ANTIQUATED_NETWORK) {
- // Create an antiquated network notification builder.
- val antiquatedNetworkNotificationBuilder = Notification.Builder(applicationContext, ANTIQUATED_NETWORK)
-
- // Set the notification to open Privacy Cell.
- antiquatedNetworkNotificationBuilder.setContentIntent(privacyCellPendingIntent)
-
- // Set the notification text.
- antiquatedNetworkNotificationBuilder.setContentText(getString(R.string.antiquated_network))
-
- // Set the notification icon.
- antiquatedNetworkNotificationBuilder.setSmallIcon(R.drawable.antiquated_notification_enabled)
-
- // Set the color.
- antiquatedNetworkNotificationBuilder.setColor(getColor(R.color.red_notification_icon))
-
- // Update the notification.
- notificationManager.notify(NOTIFICATION_ID, antiquatedNetworkNotificationBuilder.build())
-
- // Store the new network status.
- currentStatus = ANTIQUATED_NETWORK
- }
+ override fun onServiceStateChanged(serviceState: ServiceState) { // Update the voice network status.
+ // Check to see if realtime monitoring is enabled. Sometimes the system keeps running the service even when it is supposed to shut down.
+ if (sharedPreferences.getBoolean(applicationContext.getString(R.string.realtime_monitoring_key), true)) { // Realtime monitoring is enabled.
+ // 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).
+ val networkRegistrationInfo = serviceState.networkRegistrationInfoList[1]
+
+ // Get the consider 3G antiquated preference.
+ val consider3gAntiquated = sharedPreferences.getBoolean(getString(R.string.consider_3g_antiquated_key), false)
+
+ // Update the voice network security status.
+ voiceNetworkSecurityStatus = protocolHelper.checkNetwork(networkRegistrationInfo.accessNetworkTechnology, consider3gAntiquated)
+
+ // Populate the notification.
+ populateNotification()
+ } else { // Realtime monitoring is disabled.
+ // Cancel the current listener if it exists. The `PhoneStateListener` can be replaced by `TelephonyCallback` once the minimum API >= 31.
+ telephonyManager.listen(phoneStateListener, LISTEN_NONE)
+ }
+ }
+
+ @Deprecated("Deprecated in Java")
+ override fun onDisplayInfoChanged(telephonyDisplayInfo: TelephonyDisplayInfo) { // Update the data network status.
+ // Check to see if realtime monitoring is enabled. Sometimes the system keeps running the service even when it is supposed to shut down.
+ if (sharedPreferences.getBoolean(applicationContext.getString(R.string.realtime_monitoring_key), true)) { // Realtime monitoring is enabled.
+ // Get the consider 3G antiquated preference.
+ val consider3gAntiquated = sharedPreferences.getBoolean(getString(R.string.consider_3g_antiquated_key), false)
+
+ // Update the data network security status.
+ dataNetworkSecurityStatus = protocolHelper.checkNetwork(telephonyDisplayInfo.networkType, consider3gAntiquated)
+
+ // Populate the notification.
+ populateNotification()
+ } else { // Realtime monitoring is disabled.
+ // Cancel the current listener if it exists. The `PhoneStateListener` can be replaced by `TelephonyCallback` once the minimum API >= 31.
+ telephonyManager.listen(phoneStateListener, LISTEN_NONE)
}
}
}
telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_NONE)
// Listen for changes to the phone state. The `PhoneStateListener` can be replaced by `TelephonyCallback` once the minimum API >= 31.
- telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_DISPLAY_INFO_CHANGED)
+ telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_SERVICE_STATE or PhoneStateListener.LISTEN_DISPLAY_INFO_CHANGED)
+ }
+ }
+
+ fun populateNotification() {
+ // Populate the notification according to the security status.
+ if ((voiceNetworkSecurityStatus == ProtocolHelper.ANTIQUATED) || (dataNetworkSecurityStatus == ProtocolHelper.ANTIQUATED)) { // This is an antiquated network.
+ // Only update the notification if the network status has changed.
+ if (currentStatus != ANTIQUATED_NETWORK) {
+ // Create an antiquated network notification builder.
+ val antiquatedNetworkNotificationBuilder = Notification.Builder(applicationContext, ANTIQUATED_NETWORK)
+
+ // Set the notification to open Privacy Cell.
+ antiquatedNetworkNotificationBuilder.setContentIntent(privacyCellPendingIntent)
+
+ // Set the notification text.
+ antiquatedNetworkNotificationBuilder.setContentText(getString(R.string.antiquated_network))
+
+ // Set the notification icon.
+ antiquatedNetworkNotificationBuilder.setSmallIcon(R.drawable.antiquated_notification_enabled)
+
+ // Set the color.
+ antiquatedNetworkNotificationBuilder.setColor(getColor(R.color.red_notification_icon))
+
+ // Prevent swiping to dismiss the notification. This no longer works (except on the lock screen) in API >= 34.
+ antiquatedNetworkNotificationBuilder.setOngoing(true)
+
+ // Update the notification.
+ notificationManager.notify(NOTIFICATION_ID, antiquatedNetworkNotificationBuilder.build())
+
+ // Store the new network status.
+ currentStatus = ANTIQUATED_NETWORK
+ }
+ } else if ((voiceNetworkSecurityStatus == ProtocolHelper.INSECURE) || (dataNetworkSecurityStatus == ProtocolHelper.INSECURE)) { // This is an insecure network.
+ // Only update the notification if the network status has changed.
+ if (currentStatus != INSECURE_NETWORK) {
+ // Create an insecure network notification builder.
+ val insecureNetworkNotificationBuilder = Notification.Builder(applicationContext, INSECURE_NETWORK)
+
+ // Set the notification to open Privacy Cell.
+ insecureNetworkNotificationBuilder.setContentIntent(privacyCellPendingIntent)
+
+ // Set the notification text.
+ insecureNetworkNotificationBuilder.setContentText(getString(R.string.insecure_network))
+
+ // Set the notification icon.
+ insecureNetworkNotificationBuilder.setSmallIcon(R.drawable.insecure_notification_enabled)
+
+ // Set the color.
+ insecureNetworkNotificationBuilder.setColor(getColor(R.color.yellow_notification_icon))
+
+ // Prevent swiping to dismiss the notification. This no longer works (except on the lock screen) in API >= 34.
+ insecureNetworkNotificationBuilder.setOngoing(true)
+
+ // Update the notification.
+ notificationManager.notify(NOTIFICATION_ID, insecureNetworkNotificationBuilder.build())
+
+ // Store the new network status.
+ currentStatus = INSECURE_NETWORK
+ }
+ } else { // This is a secure network.
+ // Only update the notification if the network status has changed.
+ if (currentStatus != SECURE_NETWORK) {
+ // Create a secure network notification builder.
+ val secureNetworkNotificationBuilder = Notification.Builder(applicationContext, SECURE_NETWORK)
+
+ // Set the notification to open Privacy Cell.
+ secureNetworkNotificationBuilder.setContentIntent(privacyCellPendingIntent)
+
+ // Set the notification text.
+ secureNetworkNotificationBuilder.setContentText(getString(R.string.secure_network))
+
+ // Set the notification icon.
+ secureNetworkNotificationBuilder.setSmallIcon(R.drawable.secure_notification_enabled)
+
+ // Set the color.
+ secureNetworkNotificationBuilder.setColor(getColor(R.color.blue_icon))
+
+ // Prevent swiping to dismiss the notification. This no longer works (except on the lock screen) in API >= 34.
+ secureNetworkNotificationBuilder.setOngoing(true)
+
+ // Update the notification.
+ notificationManager.notify(NOTIFICATION_ID, secureNetworkNotificationBuilder.build())
+
+ // Store the new network status.
+ currentStatus = SECURE_NETWORK
+ }
}
}
-}
\ No newline at end of file
+}