3708bc225716db77487878f5a1be766cdea89218
[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.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 bottomAppBarPreference: Preference
46
47     override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
48         // Load the preferences from the XML file.
49         setPreferencesFromResource(R.xml.preferences, rootKey)
50
51         // Get a handle for the shared preferences.
52         val sharedPreferences = preferenceScreen.sharedPreferences!!
53
54         // Get handles for the preferences.
55         realtimeMonitoringPreference = findPreference(getString(R.string.realtime_monitoring_key))!!
56         val secureNetworkNotificationPreference = findPreference<Preference>(getString(R.string.secure_network_notification_key))!!
57         val insecureNetworkNotificationPreference = findPreference<Preference>(getString(R.string.insecure_network_notification_key))!!
58         bottomAppBarPreference = findPreference(getString(R.string.bottom_app_bar_key))!!
59
60         // Only enable the realtime monitoring preference if the READ_PHONE_STATE permission has been granted.
61         realtimeMonitoringPreference.isEnabled = (ActivityCompat.checkSelfPermission(requireContext(), Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED)
62
63         // Set the realtime monitoring icon according to the status.
64         if (realtimeMonitoringPreference.isEnabled) {
65             // Set the realtime monitoring preference icon.
66             if (sharedPreferences.getBoolean(getString(R.string.realtime_monitoring_key), false)) {
67                 // Set the enabled icon.
68                 realtimeMonitoringPreference.setIcon(R.drawable.realtime_monitoring_enabled)
69             } else {
70                 // Set the disabled icon.
71                 realtimeMonitoringPreference.setIcon(R.drawable.realtime_monitoring_disabled)
72             }
73         } else {
74             // Set the ghosted icon.
75             realtimeMonitoringPreference.setIcon(R.drawable.realtime_monitoring_ghosted)
76         }
77
78         // Set the notification preferences to depend on the realtime monitoring preference.
79         secureNetworkNotificationPreference.dependency = getString(R.string.realtime_monitoring_key)
80         insecureNetworkNotificationPreference.dependency = getString(R.string.realtime_monitoring_key)
81
82         // Create the notification intents.
83         val secureNetworkNotificationIntent = Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS)
84             .putExtra(Settings.EXTRA_APP_PACKAGE, requireContext().packageName)
85             .putExtra(Settings.EXTRA_CHANNEL_ID, RealtimeMonitoringService.SECURE_NETWORK)
86         val insecureNetworkNotificationIntent = Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS)
87             .putExtra(Settings.EXTRA_APP_PACKAGE, requireContext().packageName)
88             .putExtra(Settings.EXTRA_CHANNEL_ID, RealtimeMonitoringService.INSECURE_NETWORK)
89
90         // Set the notification preference intents.
91         secureNetworkNotificationPreference.intent = secureNetworkNotificationIntent
92         insecureNetworkNotificationPreference.intent = insecureNetworkNotificationIntent
93
94         // Set the bottom app bar preference icon.
95         if (sharedPreferences.getBoolean(getString(R.string.bottom_app_bar_key), false)) {
96             // Set the enabled icon.
97             bottomAppBarPreference.setIcon(R.drawable.bottom_app_bar_enabled)
98         } else {
99             // Set the disabled icon.
100             bottomAppBarPreference.setIcon(R.drawable.bottom_app_bar_disabled)
101         }
102     }
103
104     // The listener should be unregistered when the app is paused.
105     override fun onPause() {
106         // Run the default commands.
107         super.onPause()
108
109         // Get a handle for the shared preferences.
110         val sharedPreferences = preferenceScreen.sharedPreferences!!
111
112         // Unregister the shared preference listener.
113         sharedPreferences.unregisterOnSharedPreferenceChangeListener(sharedPreferenceChangeListener)
114     }
115
116     // The listener should be re-registered when the app is resumed.
117     override fun onResume() {
118         // Run the default commands.
119         super.onResume()
120
121         // Get a new shared preference change listener.
122         sharedPreferenceChangeListener = getSharedPreferenceChangeListener()
123
124         // Get a handle for the shared preferences.
125         val sharedPreferences = preferenceScreen.sharedPreferences!!
126
127         // Re-register the shared preference listener.
128         sharedPreferences.registerOnSharedPreferenceChangeListener(sharedPreferenceChangeListener)
129     }
130
131     private fun getSharedPreferenceChangeListener(): SharedPreferences.OnSharedPreferenceChangeListener {
132         // Return the shared preference change listener.
133         return SharedPreferences.OnSharedPreferenceChangeListener {sharedPreferences, key ->
134             when (key) {
135                 getString(R.string.realtime_monitoring_key) -> {
136                     // Update the icon.
137                     if (sharedPreferences.getBoolean(getString(R.string.realtime_monitoring_key), false)) {
138                         // Set the enabled icon.
139                         realtimeMonitoringPreference.setIcon(R.drawable.realtime_monitoring_enabled)
140                     } else {
141                         // Set the disabled icon.
142                         realtimeMonitoringPreference.setIcon(R.drawable.realtime_monitoring_disabled)
143                     }
144
145                     // Start or stop the service.
146                     if (sharedPreferences.getBoolean(getString(R.string.realtime_monitoring_key), false)) {  // Realtime monitoring has been enabled.
147                         // Start the realtime monitoring service.
148                         requireActivity().startService(Intent(context, RealtimeMonitoringService::class.java))
149                     } else {  // Realtime monitoring has been disabled.
150                         // Stop the realtime monitoring service.
151                         requireActivity().stopService(Intent(context, RealtimeMonitoringService::class.java))
152
153                         // Cancel the realtime listener work request.
154                         WorkManager.getInstance(requireContext()).cancelUniqueWork(getString(R.string.register_listener_work_request))
155                     }
156                 }
157
158                 getString(R.string.bottom_app_bar_key) -> {
159                     // Update the icon.
160                     if (sharedPreferences.getBoolean(getString(R.string.bottom_app_bar_key), false)) {
161                         // Set the enabled icon.
162                         bottomAppBarPreference.setIcon(R.drawable.bottom_app_bar_enabled)
163                     } else {
164                         // Set the disabled icon.
165                         bottomAppBarPreference.setIcon(R.drawable.bottom_app_bar_disabled)
166                     }
167
168                     // Create an intent to restart Privacy Cell.
169                     val restartIntent = requireActivity().parentActivityIntent!!
170
171                     // `Intent.FLAG_ACTIVITY_CLEAR_TASK` removes all activities from the stack.  It requires `Intent.FLAG_ACTIVITY_NEW_TASK`.
172                     restartIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
173
174                     // Create a handler to restart the activity.
175                     val restartHandler = Handler(Looper.getMainLooper())
176
177                     // Create a runnable to restart the activity.
178                     val restartRunnable = Runnable {
179                         // Restart the activity.
180                         startActivity(restartIntent)
181                     }
182
183                     // Restart the activity after 400 milliseconds, so that the app has enough time to save the change to the preference.
184                     restartHandler.postDelayed(restartRunnable, 400)
185                 }
186             }
187         }
188     }
189 }