2 * Copyright © 2021-2022 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.fragments
22 import android.Manifest
23 import android.content.Intent
24 import android.content.SharedPreferences
25 import android.content.pm.PackageManager
26 import android.os.Bundle
27 import android.os.Handler
28 import android.os.Looper
29 import android.provider.Settings
31 import androidx.core.app.ActivityCompat
32 import androidx.preference.Preference
33 import androidx.preference.PreferenceFragmentCompat
34 import androidx.work.WorkManager
36 import com.stoutner.privacycell.R
37 import com.stoutner.privacycell.services.RealtimeMonitoringService
39 class SettingsFragment : PreferenceFragmentCompat() {
40 // Declare the class variables.
41 private lateinit var sharedPreferenceChangeListener: SharedPreferences.OnSharedPreferenceChangeListener
43 // Declare the class views.
44 private lateinit var realtimeMonitoringPreference: Preference
45 private lateinit var secureNetworkNotificationPreference: Preference
46 private lateinit var insecureNetworkNotificationPreference: Preference
47 private lateinit var antiquatedNetworkNotificationPreference: Preference
48 private lateinit var consider3gAntiquatedPreference: Preference
49 private lateinit var bottomAppBarPreference: Preference
51 override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
52 // Load the preferences from the XML file.
53 setPreferencesFromResource(R.xml.preferences, rootKey)
55 // Get a handle for the shared preferences.
56 val sharedPreferences = preferenceScreen.sharedPreferences!!
58 // Get handles for the preferences.
59 realtimeMonitoringPreference = findPreference(getString(R.string.realtime_monitoring_key))!!
60 secureNetworkNotificationPreference = findPreference(getString(R.string.secure_network_notification_key))!!
61 insecureNetworkNotificationPreference = findPreference(getString(R.string.insecure_network_notification_key))!!
62 antiquatedNetworkNotificationPreference = findPreference(getString(R.string.antiquated_network_notification_key))!!
63 consider3gAntiquatedPreference = findPreference(getString(R.string.consider_3g_antiquated_key))!!
64 bottomAppBarPreference = findPreference(getString(R.string.bottom_app_bar_key))!!
66 // Only enable the realtime monitoring preference if the READ_PHONE_STATE permission has been granted.
67 realtimeMonitoringPreference.isEnabled = (ActivityCompat.checkSelfPermission(requireContext(), Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED)
69 // Set the realtime monitoring icon according to the status.
70 if (realtimeMonitoringPreference.isEnabled) {
71 // Set the realtime monitoring preference icon.
72 if (sharedPreferences.getBoolean(getString(R.string.realtime_monitoring_key), false)) {
74 realtimeMonitoringPreference.setIcon(R.drawable.secure_notification_enabled)
75 secureNetworkNotificationPreference.setIcon(R.drawable.secure_notification_enabled)
76 insecureNetworkNotificationPreference.setIcon(R.drawable.insecure_notification_enabled)
77 antiquatedNetworkNotificationPreference.setIcon(R.drawable.antiquated_notification_enabled)
80 realtimeMonitoringPreference.setIcon(R.drawable.secure_notification_disabled)
81 secureNetworkNotificationPreference.setIcon(R.drawable.secure_notification_disabled)
82 insecureNetworkNotificationPreference.setIcon(R.drawable.insecure_notification_disabled)
83 antiquatedNetworkNotificationPreference.setIcon(R.drawable.antiquated_notification_disabled)
87 realtimeMonitoringPreference.setIcon(R.drawable.secure_notification_ghosted)
88 secureNetworkNotificationPreference.setIcon(R.drawable.secure_notification_ghosted)
89 insecureNetworkNotificationPreference.setIcon(R.drawable.insecure_notification_ghosted)
90 antiquatedNetworkNotificationPreference.setIcon(R.drawable.antiquated_notification_ghosted)
93 // Set the notification preferences to depend on the realtime monitoring preference.
94 secureNetworkNotificationPreference.dependency = getString(R.string.realtime_monitoring_key)
95 insecureNetworkNotificationPreference.dependency = getString(R.string.realtime_monitoring_key)
96 antiquatedNetworkNotificationPreference.dependency = getString(R.string.realtime_monitoring_key)
98 // Create the notification intents.
99 val secureNetworkNotificationIntent = Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS)
100 .putExtra(Settings.EXTRA_APP_PACKAGE, requireContext().packageName)
101 .putExtra(Settings.EXTRA_CHANNEL_ID, RealtimeMonitoringService.SECURE_NETWORK)
102 val insecureNetworkNotificationIntent = Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS)
103 .putExtra(Settings.EXTRA_APP_PACKAGE, requireContext().packageName)
104 .putExtra(Settings.EXTRA_CHANNEL_ID, RealtimeMonitoringService.INSECURE_NETWORK)
105 val antiquatedNetworkNotificationIntent = Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS)
106 .putExtra(Settings.EXTRA_APP_PACKAGE, requireContext().packageName)
107 .putExtra(Settings.EXTRA_CHANNEL_ID, RealtimeMonitoringService.ANTIQUATED_NETWORK)
109 // Set the notification preference intents.
110 secureNetworkNotificationPreference.intent = secureNetworkNotificationIntent
111 insecureNetworkNotificationPreference.intent = insecureNetworkNotificationIntent
112 antiquatedNetworkNotificationPreference.intent = antiquatedNetworkNotificationIntent
114 // Set the consider 3G antiquated preference icon.
115 if (sharedPreferences.getBoolean(getString(R.string.consider_3g_antiquated_key), false)) {
116 consider3gAntiquatedPreference.setIcon(R.drawable.antiquated_3g_enabled)
118 consider3gAntiquatedPreference.setIcon(R.drawable.antiquated_3g_disabled)
121 // Set the bottom app bar preference icon.
122 if (sharedPreferences.getBoolean(getString(R.string.bottom_app_bar_key), false)) {
123 bottomAppBarPreference.setIcon(R.drawable.bottom_app_bar_enabled)
125 bottomAppBarPreference.setIcon(R.drawable.bottom_app_bar_disabled)
129 // The listener should be unregistered when the app is paused.
130 override fun onPause() {
131 // Run the default commands.
134 // Get a handle for the shared preferences.
135 val sharedPreferences = preferenceScreen.sharedPreferences!!
137 // Unregister the shared preference listener.
138 sharedPreferences.unregisterOnSharedPreferenceChangeListener(sharedPreferenceChangeListener)
141 // The listener should be re-registered when the app is resumed.
142 override fun onResume() {
143 // Run the default commands.
146 // Get a new shared preference change listener.
147 sharedPreferenceChangeListener = getSharedPreferenceChangeListener()
149 // Get a handle for the shared preferences.
150 val sharedPreferences = preferenceScreen.sharedPreferences!!
152 // Re-register the shared preference listener.
153 sharedPreferences.registerOnSharedPreferenceChangeListener(sharedPreferenceChangeListener)
156 private fun getSharedPreferenceChangeListener(): SharedPreferences.OnSharedPreferenceChangeListener {
157 // Return the shared preference change listener.
158 return SharedPreferences.OnSharedPreferenceChangeListener {sharedPreferences, key ->
160 getString(R.string.realtime_monitoring_key) -> {
162 if (sharedPreferences.getBoolean(getString(R.string.realtime_monitoring_key), false)) {
164 realtimeMonitoringPreference.setIcon(R.drawable.secure_notification_enabled)
165 secureNetworkNotificationPreference.setIcon(R.drawable.secure_notification_enabled)
166 insecureNetworkNotificationPreference.setIcon(R.drawable.insecure_notification_enabled)
167 antiquatedNetworkNotificationPreference.setIcon(R.drawable.antiquated_notification_enabled)
170 realtimeMonitoringPreference.setIcon(R.drawable.secure_notification_disabled)
171 secureNetworkNotificationPreference.setIcon(R.drawable.secure_notification_disabled)
172 insecureNetworkNotificationPreference.setIcon(R.drawable.insecure_notification_disabled)
173 antiquatedNetworkNotificationPreference.setIcon(R.drawable.antiquated_notification_disabled)
176 // Start or stop the service.
177 if (sharedPreferences.getBoolean(getString(R.string.realtime_monitoring_key), false)) { // Realtime monitoring has been enabled.
178 // Start the realtime monitoring service.
179 requireActivity().startService(Intent(context, RealtimeMonitoringService::class.java))
180 } else { // Realtime monitoring has been disabled.
181 // Stop the realtime monitoring service.
182 requireActivity().stopService(Intent(context, RealtimeMonitoringService::class.java))
184 // Cancel the realtime listener work request.
185 WorkManager.getInstance(requireContext()).cancelUniqueWork(getString(R.string.register_listener_work_request))
189 getString(R.string.consider_3g_antiquated_key) -> {
191 if (sharedPreferences.getBoolean(getString(R.string.consider_3g_antiquated_key), false)) {
192 consider3gAntiquatedPreference.setIcon(R.drawable.antiquated_3g_enabled)
194 consider3gAntiquatedPreference.setIcon(R.drawable.antiquated_3g_disabled)
197 // Restart Privacy Cell.
201 getString(R.string.bottom_app_bar_key) -> {
203 if (sharedPreferences.getBoolean(getString(R.string.bottom_app_bar_key), false)) {
204 bottomAppBarPreference.setIcon(R.drawable.bottom_app_bar_enabled)
206 bottomAppBarPreference.setIcon(R.drawable.bottom_app_bar_disabled)
209 // Restart Privacy Cell after 400 milliseconds.
216 private fun restartPrivacyCell() {
217 // Create an intent to restart Privacy Cell.
218 val restartIntent = requireActivity().parentActivityIntent!!
220 // `Intent.FLAG_ACTIVITY_CLEAR_TASK` removes all activities from the stack. It requires `Intent.FLAG_ACTIVITY_NEW_TASK`.
221 restartIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
223 // Create a handler to restart the activity.
224 val restartHandler = Handler(Looper.getMainLooper())
226 // Create a runnable to restart the activity.
227 val restartRunnable = Runnable {
228 // Restart the activity.
229 startActivity(restartIntent)
232 // Restart the activity after 400 milliseconds, so that the app has enough time to save the change to the preference.
233 restartHandler.postDelayed(restartRunnable, 400)