X-Git-Url: https://gitweb.stoutner.com/?a=blobdiff_plain;f=app%2Fsrc%2Fmain%2Fjava%2Fcom%2Fstoutner%2Fprivacycell%2Ffragments%2FSettingsFragment.kt;h=dc8545ffb0abcfa96225bc19f86dcb6f29b250b9;hb=HEAD;hp=20dfb37be3cdbb74e847fabe05125ba0b4546569;hpb=7467e75bda34246c91c4e4989b1c32a81314d53c;p=PrivacyCell.git diff --git a/app/src/main/java/com/stoutner/privacycell/fragments/SettingsFragment.kt b/app/src/main/java/com/stoutner/privacycell/fragments/SettingsFragment.kt index 20dfb37..911ab08 100644 --- a/app/src/main/java/com/stoutner/privacycell/fragments/SettingsFragment.kt +++ b/app/src/main/java/com/stoutner/privacycell/fragments/SettingsFragment.kt @@ -1,5 +1,5 @@ /* - * Copyright © 2021-2022 Soren Stoutner . + * Copyright 2021-2023 Soren Stoutner . * * This file is part of Privacy Cell . * @@ -22,7 +22,9 @@ package com.stoutner.privacycell.fragments import android.Manifest import android.content.Intent import android.content.SharedPreferences +import android.content.SharedPreferences.OnSharedPreferenceChangeListener import android.content.pm.PackageManager +import android.os.Build import android.os.Bundle import android.os.Handler import android.os.Looper @@ -34,11 +36,16 @@ import androidx.preference.PreferenceFragmentCompat import androidx.work.WorkManager import com.stoutner.privacycell.R +import com.stoutner.privacycell.activities.PrivacyCellActivity +import com.stoutner.privacycell.dialogs.NotificationPermissionDialog import com.stoutner.privacycell.services.RealtimeMonitoringService +// Define the class constants. +private const val SCROLL_Y = "scroll_y" + class SettingsFragment : PreferenceFragmentCompat() { // Declare the class variables. - private lateinit var sharedPreferenceChangeListener: SharedPreferences.OnSharedPreferenceChangeListener + private lateinit var sharedPreferenceChangeListener: OnSharedPreferenceChangeListener // Declare the class views. private lateinit var realtimeMonitoringPreference: Preference @@ -48,6 +55,12 @@ class SettingsFragment : PreferenceFragmentCompat() { private lateinit var consider3gAntiquatedPreference: Preference private lateinit var bottomAppBarPreference: Preference + companion object { + // Declare the private static class variables. For some reason (I'm looking at you Android's Activity Lifecycle) this only works if these are static. + private var fragmentRestarted: Boolean = false + private var scrollY: Int = 0 + } + override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { // Load the preferences from the XML file. setPreferencesFromResource(R.xml.preferences, rootKey) @@ -124,38 +137,20 @@ class SettingsFragment : PreferenceFragmentCompat() { } else { bottomAppBarPreference.setIcon(R.drawable.bottom_app_bar_disabled) } - } - - // The listener should be unregistered when the app is paused. - override fun onPause() { - // Run the default commands. - super.onPause() - - // Get a handle for the shared preferences. - val sharedPreferences = preferenceScreen.sharedPreferences!! - - // Unregister the shared preference listener. - sharedPreferences.unregisterOnSharedPreferenceChangeListener(sharedPreferenceChangeListener) - } - - // The listener should be re-registered when the app is resumed. - override fun onResume() { - // Run the default commands. - super.onResume() - // Get a new shared preference change listener. - sharedPreferenceChangeListener = getSharedPreferenceChangeListener() - - // Get a handle for the shared preferences. - val sharedPreferences = preferenceScreen.sharedPreferences!! + // Check if the fragment has been restarted. + if (savedInstanceState != null) { + // Set the fragment restarted flag. + fragmentRestarted = true - // Re-register the shared preference listener. - sharedPreferences.registerOnSharedPreferenceChangeListener(sharedPreferenceChangeListener) + // Save the scroll Y. + scrollY = savedInstanceState.getInt(SCROLL_Y) + } } - private fun getSharedPreferenceChangeListener(): SharedPreferences.OnSharedPreferenceChangeListener { + private fun getSharedPreferenceChangeListener(): OnSharedPreferenceChangeListener { // Return the shared preference change listener. - return SharedPreferences.OnSharedPreferenceChangeListener {sharedPreferences, key -> + return OnSharedPreferenceChangeListener { sharedPreferences: SharedPreferences, key: String? -> when (key) { getString(R.string.realtime_monitoring_key) -> { // Update the icon. @@ -175,8 +170,32 @@ class SettingsFragment : PreferenceFragmentCompat() { // Start or stop the service. if (sharedPreferences.getBoolean(getString(R.string.realtime_monitoring_key), false)) { // Realtime monitoring has been enabled. - // Start the realtime monitoring service. - requireActivity().startService(Intent(context, RealtimeMonitoringService::class.java)) + // Start the service according to the API. + if (Build.VERSION.SDK_INT >= 33) { // The device API is >= 33. + // Check to see if the post notification has been granted. + if (ActivityCompat.checkSelfPermission(requireContext(), Manifest.permission.POST_NOTIFICATIONS) == PackageManager.PERMISSION_GRANTED) { // The permission has been granted. + // Start the realtime monitoring service. + requireActivity().startService(Intent(context, RealtimeMonitoringService::class.java)) + } else { // The post notification permission has not been granted. + // Check if the user has previously denied the post notifications permission. + if (ActivityCompat.shouldShowRequestPermissionRationale(requireActivity(), Manifest.permission.POST_NOTIFICATIONS)) { // Show a dialog explaining the request first. + // Check to see if a notification permission dialog is already displayed. This happens if the app is restarted while the dialog is shown. + if (requireActivity().supportFragmentManager.findFragmentByTag(getString(R.string.notification_permission)) == null) { // No dialog is currently shown. + // Instantiate the notification permission dialog fragment. + val notificationPermissionDialogFragment = NotificationPermissionDialog() + + // Show the notification permission alert dialog. The permission will be requested when the dialog is closed. + notificationPermissionDialogFragment.show(requireActivity().supportFragmentManager, getString(R.string.notification_permission)) + } + } else { // Show the permission request directly. + // Request the post notifications permission directly. + ActivityCompat.requestPermissions(requireActivity(), arrayOf(Manifest.permission.POST_NOTIFICATIONS), PrivacyCellActivity.NOTIFICATION_PERMISSION_REQUEST_CODE) + } + } + } else { // The device API is < 33. + // Start the realtime monitoring service. + requireActivity().startService(Intent(context, RealtimeMonitoringService::class.java)) + } } else { // Realtime monitoring has been disabled. // Stop the realtime monitoring service. requireActivity().stopService(Intent(context, RealtimeMonitoringService::class.java)) @@ -213,6 +232,53 @@ class SettingsFragment : PreferenceFragmentCompat() { } } + // The listener should be unregistered when the app is paused. + override fun onPause() { + // Run the default commands. + super.onPause() + + // Get a handle for the shared preferences. + val sharedPreferences = preferenceScreen.sharedPreferences!! + + // Unregister the shared preference listener. + sharedPreferences.unregisterOnSharedPreferenceChangeListener(sharedPreferenceChangeListener) + } + + // The listener should be re-registered when the app is resumed. + override fun onResume() { + // Run the default commands. + super.onResume() + + // Get a new shared preference change listener. + sharedPreferenceChangeListener = getSharedPreferenceChangeListener() + + // Get a handle for the shared preferences. + val sharedPreferences = preferenceScreen.sharedPreferences!! + + // Re-register the shared preference listener. + sharedPreferences.registerOnSharedPreferenceChangeListener(sharedPreferenceChangeListener) + + // Update the realtime monitoring preference summary. + updateRealtimeMonitoringSummary() + + // Restore the scroll position if the fragment has been restarted. + if (fragmentRestarted) { + // Reset the fragment restarted flag. + fragmentRestarted = false + + // Set the scroll position. + listView.smoothScrollBy(0, scrollY) + } + } + + override fun onSaveInstanceState(savedInstanceState: Bundle) { + // Run the default commands. + super.onSaveInstanceState(savedInstanceState) + + // Save the scroll position. + savedInstanceState.putInt(SCROLL_Y, listView.computeVerticalScrollOffset()) + } + private fun restartPrivacyCell() { // Create an intent to restart Privacy Cell. val restartIntent = requireActivity().parentActivityIntent!! @@ -232,4 +298,18 @@ class SettingsFragment : PreferenceFragmentCompat() { // Restart the activity after 400 milliseconds, so that the app has enough time to save the change to the preference. restartHandler.postDelayed(restartRunnable, 400) } -} \ No newline at end of file + + fun updateRealtimeMonitoringSummary() { + // Update the summary according to the API. + if (Build.VERSION.SDK_INT >= 33) { // The API >= 33. + // Set the summary according to the notification permission status. + if (ActivityCompat.checkSelfPermission(requireContext(), Manifest.permission.POST_NOTIFICATIONS) == PackageManager.PERMISSION_GRANTED) + realtimeMonitoringPreference.summary = getString(R.string.realtime_monitoring_summary) + else + realtimeMonitoringPreference.summary = (getString(R.string.realtime_monitoring_summary) + " " + getString(R.string.notification_permission_denied)) + } else { // The API is < 33. + // Set the realtime monitoring summary. + realtimeMonitoringPreference.summary = getString(R.string.realtime_monitoring_summary) + } + } +}