Add a higher level warning for antiquated protocols. https://redmine.stoutner.com...
[PrivacyCell.git] / app / src / main / java / com / stoutner / privacycell / fragments / SettingsFragment.kt
1 /*
2  * Copyright © 2021-2022 Soren Stoutner <soren@stoutner.com>.
3  *
4  * This file is part of Privacy Cell <https://www.stoutner.com/privacy-cell>.
5  *
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.
10  *
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.
15  *
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/>.
18  */
19
20 package com.stoutner.privacycell.fragments
21
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
30
31 import androidx.core.app.ActivityCompat
32 import androidx.preference.Preference
33 import androidx.preference.PreferenceFragmentCompat
34 import androidx.work.WorkManager
35
36 import com.stoutner.privacycell.R
37 import com.stoutner.privacycell.services.RealtimeMonitoringService
38
39 class SettingsFragment : PreferenceFragmentCompat() {
40     // Declare the class variables.
41     private lateinit var sharedPreferenceChangeListener: SharedPreferences.OnSharedPreferenceChangeListener
42
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
50
51     override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
52         // Load the preferences from the XML file.
53         setPreferencesFromResource(R.xml.preferences, rootKey)
54
55         // Get a handle for the shared preferences.
56         val sharedPreferences = preferenceScreen.sharedPreferences!!
57
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))!!
65
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)
68
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)) {
73                 // Set the icons.
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)
78             } else {
79                 // Set the icons.
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)
84             }
85         } else {
86             // Set the icons.
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)
91         }
92
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)
97
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)
108
109         // Set the notification preference intents.
110         secureNetworkNotificationPreference.intent = secureNetworkNotificationIntent
111         insecureNetworkNotificationPreference.intent = insecureNetworkNotificationIntent
112         antiquatedNetworkNotificationPreference.intent = antiquatedNetworkNotificationIntent
113
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)
117         } else {
118             consider3gAntiquatedPreference.setIcon(R.drawable.antiquated_3g_disabled)
119         }
120
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)
124         } else {
125             bottomAppBarPreference.setIcon(R.drawable.bottom_app_bar_disabled)
126         }
127     }
128
129     // The listener should be unregistered when the app is paused.
130     override fun onPause() {
131         // Run the default commands.
132         super.onPause()
133
134         // Get a handle for the shared preferences.
135         val sharedPreferences = preferenceScreen.sharedPreferences!!
136
137         // Unregister the shared preference listener.
138         sharedPreferences.unregisterOnSharedPreferenceChangeListener(sharedPreferenceChangeListener)
139     }
140
141     // The listener should be re-registered when the app is resumed.
142     override fun onResume() {
143         // Run the default commands.
144         super.onResume()
145
146         // Get a new shared preference change listener.
147         sharedPreferenceChangeListener = getSharedPreferenceChangeListener()
148
149         // Get a handle for the shared preferences.
150         val sharedPreferences = preferenceScreen.sharedPreferences!!
151
152         // Re-register the shared preference listener.
153         sharedPreferences.registerOnSharedPreferenceChangeListener(sharedPreferenceChangeListener)
154     }
155
156     private fun getSharedPreferenceChangeListener(): SharedPreferences.OnSharedPreferenceChangeListener {
157         // Return the shared preference change listener.
158         return SharedPreferences.OnSharedPreferenceChangeListener {sharedPreferences, key ->
159             when (key) {
160                 getString(R.string.realtime_monitoring_key) -> {
161                     // Update the icon.
162                     if (sharedPreferences.getBoolean(getString(R.string.realtime_monitoring_key), false)) {
163                         // Set the icons.
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)
168                     } else {
169                         // Set the icons.
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)
174                     }
175
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))
183
184                         // Cancel the realtime listener work request.
185                         WorkManager.getInstance(requireContext()).cancelUniqueWork(getString(R.string.register_listener_work_request))
186                     }
187                 }
188
189                 getString(R.string.consider_3g_antiquated_key) -> {
190                     // Update the icon.
191                     if (sharedPreferences.getBoolean(getString(R.string.consider_3g_antiquated_key), false)) {
192                         consider3gAntiquatedPreference.setIcon(R.drawable.antiquated_3g_enabled)
193                     } else {
194                         consider3gAntiquatedPreference.setIcon(R.drawable.antiquated_3g_disabled)
195                     }
196
197                     // Restart Privacy Cell.
198                     restartPrivacyCell()
199                 }
200
201                 getString(R.string.bottom_app_bar_key) -> {
202                     // Update the icon.
203                     if (sharedPreferences.getBoolean(getString(R.string.bottom_app_bar_key), false)) {
204                         bottomAppBarPreference.setIcon(R.drawable.bottom_app_bar_enabled)
205                     } else {
206                         bottomAppBarPreference.setIcon(R.drawable.bottom_app_bar_disabled)
207                     }
208
209                     // Restart Privacy Cell after 400 milliseconds.
210                     restartPrivacyCell()
211                 }
212             }
213         }
214     }
215
216     private fun restartPrivacyCell() {
217         // Create an intent to restart Privacy Cell.
218         val restartIntent = requireActivity().parentActivityIntent!!
219
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
222
223         // Create a handler to restart the activity.
224         val restartHandler = Handler(Looper.getMainLooper())
225
226         // Create a runnable to restart the activity.
227         val restartRunnable = Runnable {
228             // Restart the activity.
229             startActivity(restartIntent)
230         }
231
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)
234     }
235 }