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 Cell. If not, see <http://www.gnu.org/licenses/>.
20 package com.stoutner.privacycell.services
22 import android.app.Notification
23 import android.app.NotificationChannel
24 import android.app.NotificationChannelGroup
25 import android.app.NotificationManager
26 import android.app.PendingIntent
27 import android.app.Service
28 import android.content.Context
29 import android.content.Intent
30 import android.os.Binder
31 import android.os.IBinder
32 import android.telephony.PhoneStateListener
33 import android.telephony.TelephonyDisplayInfo
34 import android.telephony.TelephonyManager
36 import androidx.work.ExistingPeriodicWorkPolicy
37 import androidx.work.PeriodicWorkRequestBuilder
38 import androidx.work.WorkManager
40 import com.stoutner.privacycell.R
41 import com.stoutner.privacycell.activities.PrivacyCellActivity
42 import com.stoutner.privacycell.workers.RegisterRealtimeListener
44 import java.util.concurrent.TimeUnit
46 // Define the class constants.
47 const val REALTIME_MONITORING = "realtime_monitoring"
48 const val NOTIFICATION_ID = 1
49 const val UNKNOWN_NETWORK = "unknown_network"
51 class RealtimeMonitoringService : Service() {
53 // Define the public constants. These are used in the settings fragment to launch intents to edit the sound that plays for each channel.
54 const val SECURE_NETWORK = "secure_network"
55 const val INSECURE_NETWORK = "insecure_network"
58 // Define the class variables.
59 private var currentStatus = ""
61 inner class ServiceBinder : Binder() {
62 // Get a copy of this service as a binder.
63 fun getService(): RealtimeMonitoringService = this@RealtimeMonitoringService
66 override fun onBind(intent: Intent): IBinder {
67 // Return a copy of the service binder.
68 return ServiceBinder()
71 override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
72 // Get a handle for the notification manager.
73 val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
75 // Create a notification channel group.
76 notificationManager.createNotificationChannelGroup(NotificationChannelGroup(REALTIME_MONITORING, getString(R.string.realtime_monitoring)))
78 // Prepare the notification channels.
79 val secureNetworkChannel = NotificationChannel(SECURE_NETWORK, getString(R.string.secure_network_channel), NotificationManager.IMPORTANCE_HIGH)
80 val insecureNetworkChannel = NotificationChannel(INSECURE_NETWORK, getString(R.string.insecure_network_channel), NotificationManager.IMPORTANCE_HIGH)
81 val unknownNetworkChannel = NotificationChannel(UNKNOWN_NETWORK, getString(R.string.unknown_network_channel), NotificationManager.IMPORTANCE_LOW)
83 // Set the notification channel group.
84 secureNetworkChannel.group = REALTIME_MONITORING
85 insecureNetworkChannel.group = REALTIME_MONITORING
86 unknownNetworkChannel.group = REALTIME_MONITORING
88 // Disable the notification dots.
89 secureNetworkChannel.setShowBadge(false)
90 insecureNetworkChannel.setShowBadge(false)
91 unknownNetworkChannel.setShowBadge(false)
93 // Set the notifications to be public for the secure and insecure networks.
94 secureNetworkChannel.lockscreenVisibility = Notification.VISIBILITY_PUBLIC
95 insecureNetworkChannel.lockscreenVisibility = Notification.VISIBILITY_PUBLIC
97 // Create the notification channels.
98 notificationManager.createNotificationChannel(secureNetworkChannel)
99 notificationManager.createNotificationChannel(insecureNetworkChannel)
100 notificationManager.createNotificationChannel(unknownNetworkChannel)
102 // Create a notification builder.
103 val notificationBuilder = Notification.Builder(this, UNKNOWN_NETWORK)
105 // Create an intent to open Privacy Cell.
106 val privacyCellIntent = Intent(this, PrivacyCellActivity::class.java)
108 // Create a pending intent from the Privacy Cell intent.
109 val privacyCellPendingIntent = PendingIntent.getActivity(this, 0, privacyCellIntent, PendingIntent.FLAG_IMMUTABLE)
111 // Set the notification to open Privacy Cell.
112 notificationBuilder.setContentIntent(privacyCellPendingIntent)
114 // Set the notification text.
115 notificationBuilder.setContentText(getString(R.string.unknown_network))
117 // Set the notification icon.
118 notificationBuilder.setSmallIcon(R.drawable.insecure_notification)
121 notificationBuilder.setColor(getColor(R.color.red_text))
123 // Start the foreground notification.
124 startForeground(NOTIFICATION_ID, notificationBuilder.build())
126 // Register the telephony manager listener.
127 registerTelephonyManagerListener()
129 // Create a register realtime listener work request that fires every 15 minutes with a 1 minute initial delay.
130 val registerRealtimeListenerWorkRequest = PeriodicWorkRequestBuilder<RegisterRealtimeListener>(15, TimeUnit.MINUTES).setInitialDelay(1, TimeUnit.MINUTES).build()
132 // Register the realtime listener work request.
133 WorkManager.getInstance(this).enqueueUniquePeriodicWork(getString(R.string.register_listener_work_request), ExistingPeriodicWorkPolicy.REPLACE, registerRealtimeListenerWorkRequest)
135 // Return a sticky service.
139 fun registerTelephonyManagerListener() {
140 // Get a handle for the telephony manager.
141 val telephonyManager = getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
143 // Get a handle for the notification manager.
144 val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
146 // Create an intent to open Privacy Cell.
147 val privacyCellIntent = Intent(this, PrivacyCellActivity::class.java)
149 // Create a pending intent from the Privacy Cell intent.
150 val privacyCellPendingIntent = PendingIntent.getActivity(this, 0, privacyCellIntent, PendingIntent.FLAG_IMMUTABLE)
152 // Listen for changes to the phone state.
153 telephonyManager.listen(object : PhoneStateListener() {
154 override fun onDisplayInfoChanged(telephonyDisplayInfo: TelephonyDisplayInfo) {
155 // Populate the notification according to the network type.
156 if (telephonyDisplayInfo.networkType == TelephonyManager.NETWORK_TYPE_NR) { // This is a secure 5G NR SA network.
157 // Only update the notification if the network status has changed.
158 if (currentStatus != SECURE_NETWORK) {
159 // Create a secure network notification builder.
160 val secureNetworkNotificationBuilder = Notification.Builder(applicationContext, SECURE_NETWORK)
162 // Set the notification to open Privacy Cell.
163 secureNetworkNotificationBuilder.setContentIntent(privacyCellPendingIntent)
165 // Set the notification text.
166 secureNetworkNotificationBuilder.setContentText(getString(R.string.secure_network))
168 // Set the notification icon.
169 secureNetworkNotificationBuilder.setSmallIcon(R.drawable.secure_notification)
172 secureNetworkNotificationBuilder.setColor(getColor(R.color.blue_text))
174 // Update the notification.
175 notificationManager.notify(NOTIFICATION_ID, secureNetworkNotificationBuilder.build())
177 // Store the new network status.
178 currentStatus = SECURE_NETWORK
180 } else { // This is not a secure 5G NR SA network.
181 // Only update the notification if the network status has changed.
182 if (currentStatus !=INSECURE_NETWORK) {
183 // Create an insecure network notification builder.
184 val insecureNetworkNotificationBuilder = Notification.Builder(applicationContext, INSECURE_NETWORK)
186 // Set the notification to open Privacy Cell.
187 insecureNetworkNotificationBuilder.setContentIntent(privacyCellPendingIntent)
189 // Set the notification text.
190 insecureNetworkNotificationBuilder.setContentText(getString(R.string.insecure_network))
192 // Set the notification icon.
193 insecureNetworkNotificationBuilder.setSmallIcon(R.drawable.insecure_notification)
196 insecureNetworkNotificationBuilder.setColor(getColor(R.color.red_text))
198 // Update the notification.
199 notificationManager.notify(NOTIFICATION_ID, insecureNetworkNotificationBuilder.build())
201 // Store the new network status.
202 currentStatus = INSECURE_NETWORK
206 }, PhoneStateListener.LISTEN_DISPLAY_INFO_CHANGED)