Add a realtime monitoring service. https://redmine.stoutner.com/issues/750
[PrivacyCell.git] / app / src / main / java / com / stoutner / privacycell / fragments / SettingsFragment.kt
1 /*
2  * Copyright © 2021 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.content.Intent
23 import android.content.SharedPreferences
24 import android.os.Bundle
25 import android.os.Handler
26 import android.os.Looper
27 import android.provider.Settings
28
29 import androidx.preference.Preference
30 import androidx.preference.PreferenceFragmentCompat
31
32 import com.stoutner.privacycell.R
33 import com.stoutner.privacycell.services.RealtimeMonitoringService
34
35 class SettingsFragment : PreferenceFragmentCompat() {
36     // Declare the class variables.
37     private lateinit var sharedPreferenceChangeListener: SharedPreferences.OnSharedPreferenceChangeListener
38
39     // Declare the class views.
40     private lateinit var realtimeMonitoringPreference: Preference
41     private lateinit var bottomAppBarPreference: Preference
42
43     override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
44         // Load the preferences from the XML file.
45         setPreferencesFromResource(R.xml.preferences, rootKey)
46
47         // Get a handle for the shared preferences.
48         val sharedPreferences = preferenceScreen.sharedPreferences
49
50         // Get handles for the preferences.
51         realtimeMonitoringPreference = findPreference(getString(R.string.realtime_monitoring_key))!!
52         val secureNetworkNotificationPreference = findPreference<Preference>(getString(R.string.secure_network_notification_key))!!
53         val insecureNetworkNotificationPreference = findPreference<Preference>(getString(R.string.insecure_network_notification_key))!!
54         bottomAppBarPreference = findPreference(getString(R.string.bottom_app_bar_key))!!
55
56         // Set the realtime monitoring preference icon.
57         if (sharedPreferences.getBoolean(getString(R.string.realtime_monitoring_key), false)) {
58             // Set the enabled icon.
59             realtimeMonitoringPreference.setIcon(R.drawable.realtime_monitoring_enabled)
60         } else {
61             // Set the disabled icon.
62             realtimeMonitoringPreference.setIcon(R.drawable.realtime_monitoring_disabled)
63         }
64
65         // Set the notification preferences to depend on the realtime monitoring preference.
66         secureNetworkNotificationPreference.dependency = getString(R.string.realtime_monitoring_key)
67         insecureNetworkNotificationPreference.dependency = getString(R.string.realtime_monitoring_key)
68
69         // Create the notification intents.
70         val secureNetworkNotificationIntent = Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS)
71             .putExtra(Settings.EXTRA_APP_PACKAGE, requireContext().packageName)
72             .putExtra(Settings.EXTRA_CHANNEL_ID, RealtimeMonitoringService.SECURE_NETWORK)
73         val insecureNetworkNotificationIntent = Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS)
74             .putExtra(Settings.EXTRA_APP_PACKAGE, requireContext().packageName)
75             .putExtra(Settings.EXTRA_CHANNEL_ID, RealtimeMonitoringService.INSECURE_NETWORK)
76
77         // Set the notification preference intents.
78         secureNetworkNotificationPreference.intent = secureNetworkNotificationIntent
79         insecureNetworkNotificationPreference.intent = insecureNetworkNotificationIntent
80
81         // Set the bottom app bar preference icon.
82         if (sharedPreferences.getBoolean(getString(R.string.bottom_app_bar_key), false)) {
83             // Set the enabled icon.
84             bottomAppBarPreference.setIcon(R.drawable.bottom_app_bar_enabled)
85         } else {
86             // Set the disabled icon.
87             bottomAppBarPreference.setIcon(R.drawable.bottom_app_bar_disabled)
88         }
89     }
90
91     // The listener should be unregistered when the app is paused.
92     override fun onPause() {
93         // Run the default commands.
94         super.onPause()
95
96         // Get a handle for the shared preferences.
97         val sharedPreferences = preferenceScreen.sharedPreferences
98
99         // Unregister the shared preference listener.
100         sharedPreferences.unregisterOnSharedPreferenceChangeListener(sharedPreferenceChangeListener)
101     }
102
103     // The listener should be re-registered when the app is resumed.
104     override fun onResume() {
105         // Run the default commands.
106         super.onResume()
107
108         // Get a new shared preference change listener.
109         sharedPreferenceChangeListener = getSharedPreferenceChangeListener()
110
111         // Get a handle for the shared preferences.
112         val sharedPreferences = preferenceScreen.sharedPreferences
113
114         // Re-register the shared preference listener.
115         sharedPreferences.registerOnSharedPreferenceChangeListener(sharedPreferenceChangeListener)
116     }
117
118     private fun getSharedPreferenceChangeListener(): SharedPreferences.OnSharedPreferenceChangeListener {
119         // Return the shared preference change listener.
120         return SharedPreferences.OnSharedPreferenceChangeListener {sharedPreferences, key ->
121             when (key) {
122                 getString(R.string.realtime_monitoring_key) -> {
123                     // Update the icon.
124                     if (sharedPreferences.getBoolean(getString(R.string.realtime_monitoring_key), false)) {
125                         // Set the enabled icon.
126                         realtimeMonitoringPreference.setIcon(R.drawable.realtime_monitoring_enabled)
127                     } else {
128                         // Set the disabled icon.
129                         realtimeMonitoringPreference.setIcon(R.drawable.realtime_monitoring_disabled)
130                     }
131
132                     // Start or stop the service.
133                     if (sharedPreferences.getBoolean(getString(R.string.realtime_monitoring_key), false)) {  // Realtime monitoring has been enabled.
134                         // Start the realtime monitoring service.
135                         requireActivity().startService(Intent(context, RealtimeMonitoringService::class.java))
136                     } else {  // Realtime monitoring has been disabled.
137                         // Stop the realtime monitoring service.
138                         requireActivity().stopService(Intent(context, RealtimeMonitoringService::class.java))
139                     }
140                 }
141
142                 getString(R.string.bottom_app_bar_key) -> {
143                     // Update the icon.
144                     if (sharedPreferences.getBoolean(getString(R.string.bottom_app_bar_key), false)) {
145                         // Set the enabled icon.
146                         bottomAppBarPreference.setIcon(R.drawable.bottom_app_bar_enabled)
147                     } else {
148                         // Set the disabled icon.
149                         bottomAppBarPreference.setIcon(R.drawable.bottom_app_bar_disabled)
150                     }
151
152                     // Create an intent to restart Privacy Cell.
153                     val restartIntent = requireActivity().parentActivityIntent!!
154
155                     // `Intent.FLAG_ACTIVITY_CLEAR_TASK` removes all activities from the stack.  It requires `Intent.FLAG_ACTIVITY_NEW_TASK`.
156                     restartIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
157
158                     // Create a handler to restart the activity.
159                     val restartHandler = Handler(Looper.getMainLooper())
160
161                     // Create a runnable to restart the activity.
162                     val restartRunnable = Runnable {
163                         // Restart the activity.
164                         startActivity(restartIntent)
165                     }
166
167                     // Restart the activity after 400 milliseconds, so that the app has enough time to save the change to the preference.
168                     restartHandler.postDelayed(restartRunnable, 400)
169                 }
170             }
171         }
172     }
173 }