Skip to content
Snippets Groups Projects
Unverified Commit a5505ba8 authored by Oliver Zimmerman's avatar Oliver Zimmerman Committed by GitHub
Browse files

Energy optimized and manual check warning dialogs (EXPOSUREAPP-1853) (#944)


* Check for battery saver mode

added a check for battery saver mode in connectivity helper
created sample dialog to appear if battery saver is enabled - string values to be confirmed.

* Implemented the energy saving warning dialog in main screen

- Created a Dialog in MainFragment that shows once (shared pref boolean check), and if energy saver mode is enabled
- Created a shared pref in local data to store if the energy saving warning has been shown
- Added strings required for dialog (Only DE confirmed)
- Added a method in ExternalActionHelper that will open energy saver settings
- Adjusted existing dialog in onboarding process

* Change from battery saver check to battery optimized check

- Change from battery saver check to battery optimized check
- Added second dialog explaining manual checks

* Update strings.xml

Text changes as provided on JIRA ticket

* Dialog will now only appear once in tracing settings.

* removed unused imports

* Update SettingsTracingFragment.kt

* Update SettingsTracingFragment.kt

* code formatting

* formatting

* Update ConnectivityHelper.kt

* Update SettingsTracingFragment.kt

* Lint and string file changes

1. Small corrections of brackets and lines
2. Keeping order of the elements in string files uniform across languages

* Update strings.xml

* Update strings.xml

Co-authored-by: default avatarRituraj Sambherao <git.rituraj.sambherao@gmail.com>
parent 91d5c9a7
No related branches found
No related tags found
No related merge requests found
...@@ -21,6 +21,7 @@ import de.rki.coronawarnapp.ui.viewmodel.SubmissionViewModel ...@@ -21,6 +21,7 @@ import de.rki.coronawarnapp.ui.viewmodel.SubmissionViewModel
import de.rki.coronawarnapp.ui.viewmodel.TracingViewModel import de.rki.coronawarnapp.ui.viewmodel.TracingViewModel
import de.rki.coronawarnapp.util.DialogHelper import de.rki.coronawarnapp.util.DialogHelper
import de.rki.coronawarnapp.util.ExternalActionHelper import de.rki.coronawarnapp.util.ExternalActionHelper
import de.rki.coronawarnapp.util.PowerManagementHelper
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
...@@ -71,6 +72,7 @@ class MainFragment : Fragment() { ...@@ -71,6 +72,7 @@ class MainFragment : Fragment() {
setContentDescription() setContentDescription()
showOneTimeTracingExplanationDialog() showOneTimeTracingExplanationDialog()
showEnergyOptimizedExplanationDialog()
} }
override fun onResume() { override fun onResume() {
...@@ -218,4 +220,34 @@ class MainFragment : Fragment() { ...@@ -218,4 +220,34 @@ class MainFragment : Fragment() {
} }
} }
} }
private fun showEnergyOptimizedExplanationDialog() {
// check if the dialog explaining the effects of energy saver mode were already shown and if energy saver is enabled
if (!LocalData.energyOptimizedExplanationDialogWasShown() && !PowerManagementHelper.isIgnoringBatteryOptimizations(requireActivity())) {
lifecycleScope.launch {
withContext(Dispatchers.Main) {
val dialog = DialogHelper.DialogInstance(
requireActivity(),
R.string.onboarding_energy_optimized_dialog_headline,
R.string.onboarding_energy_optimized_dialog_body,
R.string.onboarding_energy_optimized_dialog_button_positive,
R.string.onboarding_energy_optimized_dialog_button_negative,
false,
{
// go to battery optimization
ExternalActionHelper.toBatteryOptimizationSettings(requireContext())
LocalData.energyOptimizedExplanationDialogWasShown(true)
},
{
// keep battery optimization enabled
LocalData.energyOptimizedExplanationDialogWasShown(true)
})
DialogHelper.showDialog(dialog)
}
}
}
}
} }
...@@ -328,6 +328,32 @@ object LocalData { ...@@ -328,6 +328,32 @@ object LocalData {
) )
} }
/**
* Gets the boolean if the user has seen the energy saving explanation dialog
* from the EncryptedSharedPrefs
*
* @return boolean if user has seen the energy saving explanation dialog
*/
fun energyOptimizedExplanationDialogWasShown(): Boolean = getSharedPreferenceInstance().getBoolean(
CoronaWarnApplication.getAppContext()
.getString(R.string.preference_energy_optimized_explanation_shown),
false
)
/**
* Sets the boolean if the user has seen the energy saving explanation dialog
* from the EncryptedSharedPrefs
*
* @param value boolean if onboarding in relation to energy saving was completed
*/
fun energyOptimizedExplanationDialogWasShown(value: Boolean) =
getSharedPreferenceInstance().edit(true) {
putBoolean(
CoronaWarnApplication.getAppContext()
.getString(R.string.preference_energy_optimized_explanation_shown), value
)
}
/**************************************************** /****************************************************
* SERVER FETCH DATA * SERVER FETCH DATA
****************************************************/ ****************************************************/
......
...@@ -13,8 +13,11 @@ import androidx.core.app.NotificationManagerCompat ...@@ -13,8 +13,11 @@ import androidx.core.app.NotificationManagerCompat
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import de.rki.coronawarnapp.R import de.rki.coronawarnapp.R
import de.rki.coronawarnapp.databinding.FragmentOnboardingNotificationsBinding import de.rki.coronawarnapp.databinding.FragmentOnboardingNotificationsBinding
import de.rki.coronawarnapp.storage.LocalData
import de.rki.coronawarnapp.util.ConnectivityHelper import de.rki.coronawarnapp.util.ConnectivityHelper
import de.rki.coronawarnapp.util.DialogHelper import de.rki.coronawarnapp.util.DialogHelper
import de.rki.coronawarnapp.util.ExternalActionHelper
import de.rki.coronawarnapp.util.PowerManagementHelper
/** /**
* This fragment ask the user if he wants to get notifications and finishes the onboarding afterwards. * This fragment ask the user if he wants to get notifications and finishes the onboarding afterwards.
...@@ -66,6 +69,14 @@ class OnboardingNotificationsFragment : Fragment() { ...@@ -66,6 +69,14 @@ class OnboardingNotificationsFragment : Fragment() {
private fun checkForBackgroundJobDisabled() { private fun checkForBackgroundJobDisabled() {
if (!ConnectivityHelper.isBackgroundJobEnabled(requireActivity())) { if (!ConnectivityHelper.isBackgroundJobEnabled(requireActivity())) {
showBackgroundJobDisabledNotification() showBackgroundJobDisabledNotification()
} else {
checkForEnergyOptimizedEnabled()
}
}
private fun checkForEnergyOptimizedEnabled() {
if (!PowerManagementHelper.isIgnoringBatteryOptimizations(requireActivity())) {
showEnergyOptimizedEnabledForBackground()
} else { } else {
navigateToMain() navigateToMain()
} }
...@@ -78,21 +89,56 @@ class OnboardingNotificationsFragment : Fragment() { ...@@ -78,21 +89,56 @@ class OnboardingNotificationsFragment : Fragment() {
R.string.onboarding_background_fetch_dialog_body, R.string.onboarding_background_fetch_dialog_body,
R.string.onboarding_background_fetch_dialog_button_positive, R.string.onboarding_background_fetch_dialog_button_positive,
R.string.onboarding_background_fetch_dialog_button_negative, R.string.onboarding_background_fetch_dialog_button_negative,
false, false, {
{
val intent = Intent( val intent = Intent(
ACTION_APPLICATION_DETAILS_SETTINGS, ACTION_APPLICATION_DETAILS_SETTINGS,
Uri.fromParts("package", requireContext().packageName, null) Uri.fromParts("package", requireContext().packageName, null)
) )
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
startActivity(intent) startActivity(intent)
}, // show battery optimization system dialog after background processing dialog
{ checkForEnergyOptimizedEnabled()
}, {
// declined, show additional dialog explaining manual risk calculation
showManualCheckingRequiredDialog()
})
DialogHelper.showDialog(dialog)
}
private fun showEnergyOptimizedEnabledForBackground() {
val dialog = DialogHelper.DialogInstance(
requireActivity(),
R.string.onboarding_energy_optimized_dialog_headline,
R.string.onboarding_energy_optimized_dialog_body,
R.string.onboarding_energy_optimized_dialog_button_positive,
R.string.onboarding_energy_optimized_dialog_button_negative,
false, {
// go to battery optimization
ExternalActionHelper.toBatteryOptimizationSettings(requireContext())
LocalData.energyOptimizedExplanationDialogWasShown(true)
navigateToMain() navigateToMain()
}, {
// keep battery optimization enabled
LocalData.energyOptimizedExplanationDialogWasShown(true)
showManualCheckingRequiredDialog()
}) })
DialogHelper.showDialog(dialog) DialogHelper.showDialog(dialog)
} }
private fun showManualCheckingRequiredDialog() {
val dialog = DialogHelper.DialogInstance(
requireActivity(),
R.string.onboarding_manual_required_dialog_headline,
R.string.onboarding_manual_required_dialog_body,
R.string.onboarding_manual_required_dialog_button,
null,
false, {
navigateToMain()
}
)
DialogHelper.showDialog(dialog)
}
private fun navigateToMain() { private fun navigateToMain() {
(requireActivity() as OnboardingActivity).completeOnboarding() (requireActivity() as OnboardingActivity).completeOnboarding()
} }
......
...@@ -16,16 +16,15 @@ import de.rki.coronawarnapp.exception.reporting.report ...@@ -16,16 +16,15 @@ import de.rki.coronawarnapp.exception.reporting.report
import de.rki.coronawarnapp.nearby.InternalExposureNotificationClient import de.rki.coronawarnapp.nearby.InternalExposureNotificationClient
import de.rki.coronawarnapp.nearby.InternalExposureNotificationPermissionHelper import de.rki.coronawarnapp.nearby.InternalExposureNotificationPermissionHelper
import de.rki.coronawarnapp.storage.LocalData import de.rki.coronawarnapp.storage.LocalData
import de.rki.coronawarnapp.storage.SettingsRepository.isLocationEnabled
import de.rki.coronawarnapp.ui.main.MainActivity import de.rki.coronawarnapp.ui.main.MainActivity
import de.rki.coronawarnapp.ui.viewmodel.SettingsViewModel import de.rki.coronawarnapp.ui.viewmodel.SettingsViewModel
import de.rki.coronawarnapp.ui.viewmodel.TracingViewModel import de.rki.coronawarnapp.ui.viewmodel.TracingViewModel
import de.rki.coronawarnapp.util.DialogHelper import de.rki.coronawarnapp.util.DialogHelper
import de.rki.coronawarnapp.util.ExternalActionHelper import de.rki.coronawarnapp.util.ExternalActionHelper
import de.rki.coronawarnapp.util.IGNORE_CHANGE_TAG import de.rki.coronawarnapp.util.IGNORE_CHANGE_TAG
import de.rki.coronawarnapp.util.PowerManagementHelper
import de.rki.coronawarnapp.util.formatter.formatTracingSwitchEnabled import de.rki.coronawarnapp.util.formatter.formatTracingSwitchEnabled
import de.rki.coronawarnapp.worker.BackgroundWorkScheduler import de.rki.coronawarnapp.worker.BackgroundWorkScheduler
import kotlinx.android.synthetic.main.fragment_settings_tracing.view.*
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
/** /**
...@@ -162,6 +161,10 @@ class SettingsTracingFragment : Fragment(), ...@@ -162,6 +161,10 @@ class SettingsTracingFragment : Fragment(),
// ask for consent via dialog for initial tracing activation when tracing was not // ask for consent via dialog for initial tracing activation when tracing was not
// activated during onboarding // activated during onboarding
showConsentDialog() showConsentDialog()
// check if background processing is switched off, if it is, show the manual calculation dialog explanation before turning on.
if (!PowerManagementHelper.isIgnoringBatteryOptimizations(requireActivity())) {
showManualCheckingRequiredDialog()
}
} }
} }
} catch (exception: Exception) { } catch (exception: Exception) {
...@@ -175,6 +178,20 @@ class SettingsTracingFragment : Fragment(), ...@@ -175,6 +178,20 @@ class SettingsTracingFragment : Fragment(),
} }
} }
private fun showManualCheckingRequiredDialog() {
val dialog = DialogHelper.DialogInstance(
requireActivity(),
R.string.onboarding_manual_required_dialog_headline,
R.string.onboarding_manual_required_dialog_body,
R.string.onboarding_manual_required_dialog_button,
null,
false, {
// close dialog
}
)
DialogHelper.showDialog(dialog)
}
private fun showConsentDialog() { private fun showConsentDialog() {
val dialog = DialogHelper.DialogInstance( val dialog = DialogHelper.DialogInstance(
requireActivity(), requireActivity(),
...@@ -182,8 +199,7 @@ class SettingsTracingFragment : Fragment(), ...@@ -182,8 +199,7 @@ class SettingsTracingFragment : Fragment(),
R.string.onboarding_tracing_body_consent, R.string.onboarding_tracing_body_consent,
R.string.onboarding_button_enable, R.string.onboarding_button_enable,
R.string.onboarding_button_cancel, R.string.onboarding_button_cancel,
true, true, {
{
internalExposureNotificationPermissionHelper.requestPermissionToStartTracing() internalExposureNotificationPermissionHelper.requestPermissionToStartTracing()
}, { }, {
tracingViewModel.refreshIsTracingEnabled() tracingViewModel.refreshIsTracingEnabled()
......
...@@ -184,4 +184,17 @@ object ExternalActionHelper { ...@@ -184,4 +184,17 @@ object ExternalActionHelper {
) )
} }
} }
fun toBatterySaverSettings(context: Context) {
try {
val intent = Intent(Settings.ACTION_BATTERY_SAVER_SETTINGS)
context.startActivity(intent)
} catch (exception: Exception) {
// catch generic exception on settings navigation
// most likely due to device / rom specific intent issue
ExternalActionException(exception).report(
ExceptionCategory.UI
)
}
}
} }
...@@ -415,6 +415,20 @@ ...@@ -415,6 +415,20 @@
<string name="onboarding_background_fetch_dialog_button_positive">"Geräteeinstellungen öffnen"</string> <string name="onboarding_background_fetch_dialog_button_positive">"Geräteeinstellungen öffnen"</string>
<!-- XBUT: onboarding(tracing) - dialog about background jobs, continue in app --> <!-- XBUT: onboarding(tracing) - dialog about background jobs, continue in app -->
<string name="onboarding_background_fetch_dialog_button_negative">"Risiko-Ermittlung manuell starten"</string> <string name="onboarding_background_fetch_dialog_button_negative">"Risiko-Ermittlung manuell starten"</string>
<!-- XACT: onboarding(tracing) - dialog about energy optimized header text -->
<string name="onboarding_energy_optimized_dialog_headline">"Priorisierte Hintergrundaktivität erlauben"</string>
<!-- YMSI: onboarding(tracing) - dialog about energy optimized -->
<string name="onboarding_energy_optimized_dialog_body">"Erlauben Sie die priorisierte Hintergrundaktivität, damit die App jederzeit Ihren Risikostatus im Hintergrund ermitteln kann (empfohlen). Damit wird die Optimierung des Akku-Verbrauchs ausschließlich für die Corona-Warn-App deaktiviert. Ein stark erhöhter Akku-Verbrauch ist hierbei nicht zu erwarten. \n\nWenn Sie diese Einstellung nicht erlauben, müssen Sie Ihren Risikostatus manuell in der App aktualisieren."</string>
<!-- XBUT: onboarding(tracing) - dialog about energy optimized, open device settings -->
<string name="onboarding_energy_optimized_dialog_button_positive">"Erlauben"</string>
<!-- XBUT: onboarding(tracing) - dialog about energy optimized, continue in app -->
<string name="onboarding_energy_optimized_dialog_button_negative">"Nicht erlauben"</string>
<!-- XACT: onboarding(tracing) - dialog about manual checking header text -->
<string name="onboarding_manual_required_dialog_headline">"Priorisierte Hintergrundaktivität deaktiviert"</string>
<!-- YMSI: onboarding(tracing) - dialog about manual checking -->
<string name="onboarding_manual_required_dialog_body">"Beachten Sie, dass Sie ohne Aktivierung der priorisierten Hintergrundaktivität die App einmal am Tag aufrufen müssen, um Ihren Risikostatus manuell aktualisieren zu können. \n\nSie können die priorisierte Hintergrundaktivität jederzeit in Ihren Einstellungen aktivieren. "</string>
<!-- XBUT: onboarding(tracing) - dialog about manual checking button -->
<string name="onboarding_manual_required_dialog_button">"Ok"</string>
<!-- XACT: onboarding(tracing) - illustraction description, header image --> <!-- XACT: onboarding(tracing) - illustraction description, header image -->
<string name="onboarding_tracing_illustration_description">"Drei Personen haben die Risiko-Ermittlung auf ihren Smartphones aktiviert, ihre Begegnung wird daher aufgezeichnet."</string> <string name="onboarding_tracing_illustration_description">"Drei Personen haben die Risiko-Ermittlung auf ihren Smartphones aktiviert, ihre Begegnung wird daher aufgezeichnet."</string>
<!-- XHED: onboarding(tracing) - location explanation for bluetooth headline --> <!-- XHED: onboarding(tracing) - location explanation for bluetooth headline -->
......
...@@ -71,6 +71,8 @@ ...@@ -71,6 +71,8 @@
<string name="preference_test_result_notification"><xliff:g id="preference">"preference_test_result_notification"</xliff:g></string> <string name="preference_test_result_notification"><xliff:g id="preference">"preference_test_result_notification"</xliff:g></string>
<!-- NOTR --> <!-- NOTR -->
<string name="preference_risk_days_explanation_shown"><xliff:g id="preference">"preference_risk_days_explanation_shown"</xliff:g></string> <string name="preference_risk_days_explanation_shown"><xliff:g id="preference">"preference_risk_days_explanation_shown"</xliff:g></string>
<!-- NOTR -->
<string name="preference_energy_optimized_explanation_shown"><xliff:g id="preference">"preference_energy_optimized_explanation_shown"</xliff:g></string>
<!-- #################################### <!-- ####################################
Generics Generics
...@@ -415,6 +417,20 @@ ...@@ -415,6 +417,20 @@
<string name="onboarding_background_fetch_dialog_button_positive">"Open Device Settings"</string> <string name="onboarding_background_fetch_dialog_button_positive">"Open Device Settings"</string>
<!-- XBUT: onboarding(tracing) - dialog about background jobs, continue in app --> <!-- XBUT: onboarding(tracing) - dialog about background jobs, continue in app -->
<string name="onboarding_background_fetch_dialog_button_negative">"Start Exposure Logging Manually"</string> <string name="onboarding_background_fetch_dialog_button_negative">"Start Exposure Logging Manually"</string>
<!-- XACT: onboarding(tracing) - dialog about energy optimized header text -->
<string name="onboarding_energy_optimized_dialog_headline">""</string>
<!-- YMSI: onboarding(tracing) - dialog about energy optimized -->
<string name="onboarding_energy_optimized_dialog_body">""</string>
<!-- XBUT: onboarding(tracing) - dialog about energy optimized, open device settings -->
<string name="onboarding_energy_optimized_dialog_button_positive">""</string>
<!-- XBUT: onboarding(tracing) - dialog about energy optimized, continue in app -->
<string name="onboarding_energy_optimized_dialog_button_negative">""</string>
<!-- XACT: onboarding(tracing) - dialog about manual checking header text -->
<string name="onboarding_manual_required_dialog_headline">""</string>
<!-- YMSI: onboarding(tracing) - dialog about manual checking -->
<string name="onboarding_manual_required_dialog_body">""</string>
<!-- XBUT: onboarding(tracing) - dialog about manual checking button -->
<string name="onboarding_manual_required_dialog_button">"Ok"</string>
<!-- XACT: onboarding(tracing) - illustraction description, header image --> <!-- XACT: onboarding(tracing) - illustraction description, header image -->
<string name="onboarding_tracing_illustration_description">"Three people have activated exposure logging on their devices, which will log their encounters with each other."</string> <string name="onboarding_tracing_illustration_description">"Three people have activated exposure logging on their devices, which will log their encounters with each other."</string>
<!-- XHED: onboarding(tracing) - location explanation for bluetooth headline --> <!-- XHED: onboarding(tracing) - location explanation for bluetooth headline -->
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment