From 22c9702aaf782c09b7539ba89e5c9bc597e78bd2 Mon Sep 17 00:00:00 2001
From: Kolya Opahle <k.opahle@sap.com>
Date: Thu, 30 Jul 2020 17:59:38 +0200
Subject: [PATCH] Fix looping background restricition notification in
 onboarding (EXPOSUREAPP-1962) (#950)

* added call to navigateToMain before opening the app settings

* Moved checks for background job notification to main activity

* refined background dialogs

Co-authored-by: Philipp Woessner <philipp.woessner@sap.com>
---
 .../ui/main/MainFragment.kt                   | 32 -------
 .../de/rki/coronawarnapp/storage/LocalData.kt | 50 ++++++-----
 .../rki/coronawarnapp/ui/main/MainActivity.kt | 76 +++++++++++++++++
 .../OnboardingNotificationsFragment.kt        | 84 +------------------
 .../coronawarnapp/util/ConnectivityHelper.kt  | 22 ++++-
 .../src/main/res/values-bg/strings.xml        |  2 +
 .../src/main/res/values-de/strings.xml        |  2 +
 .../src/main/res/values-en/strings.xml        |  2 +
 .../src/main/res/values-pl/strings.xml        |  2 +
 .../src/main/res/values-ro/strings.xml        |  2 +
 .../src/main/res/values-tr/strings.xml        |  2 +
 .../src/main/res/values/strings.xml           |  4 +-
 12 files changed, 133 insertions(+), 147 deletions(-)

diff --git a/Corona-Warn-App/src/device/java/de.rki.coronawarnapp/ui/main/MainFragment.kt b/Corona-Warn-App/src/device/java/de.rki.coronawarnapp/ui/main/MainFragment.kt
index f0707b0ae..ec73b7aa8 100644
--- a/Corona-Warn-App/src/device/java/de.rki.coronawarnapp/ui/main/MainFragment.kt
+++ b/Corona-Warn-App/src/device/java/de.rki.coronawarnapp/ui/main/MainFragment.kt
@@ -21,7 +21,6 @@ import de.rki.coronawarnapp.ui.viewmodel.SubmissionViewModel
 import de.rki.coronawarnapp.ui.viewmodel.TracingViewModel
 import de.rki.coronawarnapp.util.DialogHelper
 import de.rki.coronawarnapp.util.ExternalActionHelper
-import de.rki.coronawarnapp.util.PowerManagementHelper
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.withContext
@@ -72,7 +71,6 @@ class MainFragment : Fragment() {
         setContentDescription()
 
         showOneTimeTracingExplanationDialog()
-        showEnergyOptimizedExplanationDialog()
     }
 
     override fun onResume() {
@@ -220,34 +218,4 @@ 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)
-                }
-            }
-        }
-    }
 }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/LocalData.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/LocalData.kt
index e952683d9..889ab5669 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/LocalData.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/LocalData.kt
@@ -73,6 +73,30 @@ object LocalData {
                 .getString(R.string.preference_onboarding_completed_timestamp), value
         )
     }
+
+    /**
+     * Gets the boolean if the user has received the background warning
+     * from the EncryptedSharedPrefs
+     *
+     * @return boolean if background warning was shown
+     */
+    fun isBackgroundCheckDone(): Boolean = getSharedPreferenceInstance().getBoolean(
+        CoronaWarnApplication.getAppContext().getString(R.string.preference_background_check_done),
+        false
+    )
+
+    /**
+     * Sets the boolean if the user has received the background warning
+     * from the EncryptedSharedPrefs
+     *
+     * @param value boolean if background warning was shown
+     */
+    fun isBackgroundCheckDone(value: Boolean) = getSharedPreferenceInstance().edit(true) {
+        putBoolean(
+            CoronaWarnApplication.getAppContext()
+                .getString(R.string.preference_background_check_done), value
+        )
+    }
     /****************************************************
      * TRACING DATA
      ****************************************************/
@@ -328,32 +352,6 @@ 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
      ****************************************************/
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/MainActivity.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/MainActivity.kt
index afb0a44be..21aab5b52 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/MainActivity.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/MainActivity.kt
@@ -2,14 +2,20 @@ package de.rki.coronawarnapp.ui.main
 
 import android.content.Context
 import android.content.Intent
+import android.net.Uri
 import android.os.Bundle
+import android.provider.Settings
 import androidx.appcompat.app.AppCompatActivity
 import androidx.fragment.app.Fragment
 import androidx.fragment.app.FragmentManager
 import androidx.lifecycle.ViewModelProviders
 import de.rki.coronawarnapp.R
+import de.rki.coronawarnapp.storage.LocalData
 import de.rki.coronawarnapp.ui.viewmodel.SettingsViewModel
 import de.rki.coronawarnapp.util.ConnectivityHelper
+import de.rki.coronawarnapp.util.DialogHelper
+import de.rki.coronawarnapp.util.ExternalActionHelper
+import de.rki.coronawarnapp.util.PowerManagementHelper
 import de.rki.coronawarnapp.worker.BackgroundWorkScheduler
 
 /**
@@ -89,6 +95,76 @@ class MainActivity : AppCompatActivity() {
         ConnectivityHelper.registerLocationStatusCallback(this, callbackLocation)
         settingsViewModel.updateBackgroundJobEnabled(ConnectivityHelper.isBackgroundJobEnabled(this))
         scheduleWork()
+        checkShouldDisplayBackgroundWarning()
+    }
+
+    private fun showEnergyOptimizedEnabledForBackground() {
+        val dialog = DialogHelper.DialogInstance(
+            this,
+            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.disableBatteryOptimizations(this)
+            }, {
+                // keep battery optimization enabled
+                showManualCheckingRequiredDialog()
+            })
+        DialogHelper.showDialog(dialog)
+    }
+
+    private fun checkForEnergyOptimizedEnabled() {
+        if (!PowerManagementHelper.isIgnoringBatteryOptimizations(this)) {
+            showEnergyOptimizedEnabledForBackground()
+        }
+    }
+
+    private fun showManualCheckingRequiredDialog() {
+        val dialog = DialogHelper.DialogInstance(
+            this,
+            R.string.onboarding_manual_required_dialog_headline,
+            R.string.onboarding_manual_required_dialog_body,
+            R.string.onboarding_manual_required_dialog_button,
+            null,
+            false
+        )
+        DialogHelper.showDialog(dialog)
+    }
+
+    private fun showBackgroundJobDisabledNotification() {
+        val dialog = DialogHelper.DialogInstance(
+            this,
+            R.string.onboarding_background_fetch_dialog_headline,
+            R.string.onboarding_background_fetch_dialog_body,
+            R.string.onboarding_background_fetch_dialog_button_positive,
+            R.string.onboarding_background_fetch_dialog_button_negative,
+            false, {
+                val intent = Intent(
+                    Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
+                    Uri.fromParts("package", packageName, null)
+                )
+                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+                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 checkShouldDisplayBackgroundWarning() {
+        if (!LocalData.isBackgroundCheckDone()) {
+            LocalData.isBackgroundCheckDone(true)
+            if (ConnectivityHelper.isBackgroundRestricted(this)) {
+                showBackgroundJobDisabledNotification()
+            } else {
+                checkForEnergyOptimizedEnabled()
+            }
+        }
     }
 
     /**
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingNotificationsFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingNotificationsFragment.kt
index 78b41cb72..c6768a15f 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingNotificationsFragment.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/onboarding/OnboardingNotificationsFragment.kt
@@ -1,9 +1,6 @@
 package de.rki.coronawarnapp.ui.onboarding
 
-import android.content.Intent
-import android.net.Uri
 import android.os.Bundle
-import android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS
 import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
@@ -11,13 +8,7 @@ import android.view.accessibility.AccessibilityEvent
 import androidx.appcompat.app.AlertDialog
 import androidx.core.app.NotificationManagerCompat
 import androidx.fragment.app.Fragment
-import de.rki.coronawarnapp.R
 import de.rki.coronawarnapp.databinding.FragmentOnboardingNotificationsBinding
-import de.rki.coronawarnapp.storage.LocalData
-import de.rki.coronawarnapp.util.ConnectivityHelper
-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.
@@ -59,86 +50,13 @@ class OnboardingNotificationsFragment : Fragment() {
 
     private fun setButtonOnClickListener() {
         binding.onboardingButtonNext.setOnClickListener {
-            checkForBackgroundJobDisabled()
+            navigateToMain()
         }
         binding.onboardingButtonBack.buttonIcon.setOnClickListener {
             (activity as OnboardingActivity).goBack()
         }
     }
 
-    private fun checkForBackgroundJobDisabled() {
-        if (!ConnectivityHelper.isBackgroundJobEnabled(requireActivity())) {
-            showBackgroundJobDisabledNotification()
-        } else {
-            checkForEnergyOptimizedEnabled()
-        }
-    }
-
-    private fun checkForEnergyOptimizedEnabled() {
-        if (!PowerManagementHelper.isIgnoringBatteryOptimizations(requireActivity())) {
-            showEnergyOptimizedEnabledForBackground()
-        } else {
-            navigateToMain()
-        }
-    }
-
-    private fun showBackgroundJobDisabledNotification() {
-        val dialog = DialogHelper.DialogInstance(
-            requireActivity(),
-            R.string.onboarding_background_fetch_dialog_headline,
-            R.string.onboarding_background_fetch_dialog_body,
-            R.string.onboarding_background_fetch_dialog_button_positive,
-            R.string.onboarding_background_fetch_dialog_button_negative,
-            false, {
-                val intent = Intent(
-                    ACTION_APPLICATION_DETAILS_SETTINGS,
-                    Uri.fromParts("package", requireContext().packageName, null)
-                )
-                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
-                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()
-            }, {
-                // keep battery optimization enabled
-                LocalData.energyOptimizedExplanationDialogWasShown(true)
-                showManualCheckingRequiredDialog()
-            })
-        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() {
         (requireActivity() as OnboardingActivity).completeOnboarding()
     }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/ConnectivityHelper.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/ConnectivityHelper.kt
index b111fec8a..da39aa39b 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/ConnectivityHelper.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/ConnectivityHelper.kt
@@ -191,14 +191,28 @@ object ConnectivityHelper {
      * @param context the context
      *
      * @return Boolean
+     */
+    fun isBackgroundRestricted(context: Context): Boolean {
+        val activityManager = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
+        return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
+            activityManager.isBackgroundRestricted
+        } else false
+    }
+
+    /**
+     * Background jobs are enabled only if the battery optimization is enabled and
+     * the background activity is not restricted
+     *
+     * @param context the context
+     *
+     * @return Boolean
      *
      * @see isBackgroundRestricted
      */
     fun isBackgroundJobEnabled(context: Context): Boolean {
-        val activityManager = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
-        return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
-            !activityManager.isBackgroundRestricted && PowerManagementHelper.isIgnoringBatteryOptimizations(context)
-        } else true
+        return !isBackgroundRestricted(context) && PowerManagementHelper.isIgnoringBatteryOptimizations(
+            context
+        )
     }
 
     /**
diff --git a/Corona-Warn-App/src/main/res/values-bg/strings.xml b/Corona-Warn-App/src/main/res/values-bg/strings.xml
index 94a189e86..01d0307c6 100644
--- a/Corona-Warn-App/src/main/res/values-bg/strings.xml
+++ b/Corona-Warn-App/src/main/res/values-bg/strings.xml
@@ -12,6 +12,8 @@
     <!-- NOTR -->
     <string name="preference_onboarding_completed_timestamp"><xliff:g id="preference">"preference_onboarding_completed_timestamp"</xliff:g></string>
     <!-- NOTR -->
+    <string name="preference_background_check_done"><xliff:g id="preference">"preference_background_check_done"</xliff:g></string>
+    <!-- NOTR -->
     <string name="preference_reset_app"><xliff:g id="preference">"preference_reset_app"</xliff:g></string>
     <!-- NOTR -->
     <string name="preference_only_wifi"><xliff:g id="preference">"preference_only_wifi"</xliff:g></string>
diff --git a/Corona-Warn-App/src/main/res/values-de/strings.xml b/Corona-Warn-App/src/main/res/values-de/strings.xml
index 3249261a3..803710aef 100644
--- a/Corona-Warn-App/src/main/res/values-de/strings.xml
+++ b/Corona-Warn-App/src/main/res/values-de/strings.xml
@@ -12,6 +12,8 @@
     <!-- NOTR -->
     <string name="preference_onboarding_completed_timestamp"><xliff:g id="preference">"preference_onboarding_completed_timestamp"</xliff:g></string>
     <!-- NOTR -->
+    <string name="preference_background_check_done"><xliff:g id="preference">"preference_background_check_done"</xliff:g></string>
+    <!-- NOTR -->
     <string name="preference_reset_app"><xliff:g id="preference">"preference_reset_app"</xliff:g></string>
     <!-- NOTR -->
     <string name="preference_only_wifi"><xliff:g id="preference">"preference_only_wifi"</xliff:g></string>
diff --git a/Corona-Warn-App/src/main/res/values-en/strings.xml b/Corona-Warn-App/src/main/res/values-en/strings.xml
index b9a428cc1..9a82b6a5e 100644
--- a/Corona-Warn-App/src/main/res/values-en/strings.xml
+++ b/Corona-Warn-App/src/main/res/values-en/strings.xml
@@ -12,6 +12,8 @@
     <!-- NOTR -->
     <string name="preference_onboarding_completed_timestamp"><xliff:g id="preference">"preference_onboarding_completed_timestamp"</xliff:g></string>
     <!-- NOTR -->
+    <string name="preference_background_check_done"><xliff:g id="preference">"preference_background_check_done"</xliff:g></string>
+    <!-- NOTR -->
     <string name="preference_reset_app"><xliff:g id="preference">"preference_reset_app"</xliff:g></string>
     <!-- NOTR -->
     <string name="preference_only_wifi"><xliff:g id="preference">"preference_only_wifi"</xliff:g></string>
diff --git a/Corona-Warn-App/src/main/res/values-pl/strings.xml b/Corona-Warn-App/src/main/res/values-pl/strings.xml
index 12e66aa35..61cd21496 100644
--- a/Corona-Warn-App/src/main/res/values-pl/strings.xml
+++ b/Corona-Warn-App/src/main/res/values-pl/strings.xml
@@ -12,6 +12,8 @@
     <!-- NOTR -->
     <string name="preference_onboarding_completed_timestamp"><xliff:g id="preference">"preference_onboarding_completed_timestamp"</xliff:g></string>
     <!-- NOTR -->
+    <string name="preference_background_check_done"><xliff:g id="preference">"preference_background_check_done"</xliff:g></string>
+    <!-- NOTR -->
     <string name="preference_reset_app"><xliff:g id="preference">"preference_reset_app"</xliff:g></string>
     <!-- NOTR -->
     <string name="preference_only_wifi"><xliff:g id="preference">"preference_only_wifi"</xliff:g></string>
diff --git a/Corona-Warn-App/src/main/res/values-ro/strings.xml b/Corona-Warn-App/src/main/res/values-ro/strings.xml
index 910694562..f67be6a34 100644
--- a/Corona-Warn-App/src/main/res/values-ro/strings.xml
+++ b/Corona-Warn-App/src/main/res/values-ro/strings.xml
@@ -12,6 +12,8 @@
     <!-- NOTR -->
     <string name="preference_onboarding_completed_timestamp"><xliff:g id="preference">"preference_onboarding_completed_timestamp"</xliff:g></string>
     <!-- NOTR -->
+    <string name="preference_background_check_done"><xliff:g id="preference">"preference_background_check_done"</xliff:g></string>
+    <!-- NOTR -->
     <string name="preference_reset_app"><xliff:g id="preference">"preference_reset_app"</xliff:g></string>
     <!-- NOTR -->
     <string name="preference_only_wifi"><xliff:g id="preference">"preference_only_wifi"</xliff:g></string>
diff --git a/Corona-Warn-App/src/main/res/values-tr/strings.xml b/Corona-Warn-App/src/main/res/values-tr/strings.xml
index de46267b6..9e009842d 100644
--- a/Corona-Warn-App/src/main/res/values-tr/strings.xml
+++ b/Corona-Warn-App/src/main/res/values-tr/strings.xml
@@ -12,6 +12,8 @@
     <!-- NOTR -->
     <string name="preference_onboarding_completed_timestamp"><xliff:g id="preference">"preference_onboarding_completed_timestamp"</xliff:g></string>
     <!-- NOTR -->
+    <string name="preference_background_check_done"><xliff:g id="preference">"preference_background_check_done"</xliff:g></string>
+    <!-- NOTR -->
     <string name="preference_reset_app"><xliff:g id="preference">"preference_reset_app"</xliff:g></string>
     <!-- NOTR -->
     <string name="preference_only_wifi"><xliff:g id="preference">"preference_only_wifi"</xliff:g></string>
diff --git a/Corona-Warn-App/src/main/res/values/strings.xml b/Corona-Warn-App/src/main/res/values/strings.xml
index cf22866d9..92c978486 100644
--- a/Corona-Warn-App/src/main/res/values/strings.xml
+++ b/Corona-Warn-App/src/main/res/values/strings.xml
@@ -12,6 +12,8 @@
     <!-- NOTR -->
     <string name="preference_onboarding_completed_timestamp"><xliff:g id="preference">"preference_onboarding_completed_timestamp"</xliff:g></string>
     <!-- NOTR -->
+    <string name="preference_background_check_done"><xliff:g id="preference">"preference_background_check_done"</xliff:g></string>
+    <!-- NOTR -->
     <string name="preference_reset_app"><xliff:g id="preference">"preference_reset_app"</xliff:g></string>
     <!-- NOTR -->
     <string name="preference_only_wifi"><xliff:g id="preference">"preference_only_wifi"</xliff:g></string>
@@ -73,8 +75,6 @@
     <string name="preference_risk_days_explanation_shown"><xliff:g id="preference">"preference_risk_days_explanation_shown"</xliff:g></string>
     <!-- NOTR -->
     <string name="preference_background_notification"><xliff:g id="preference">"preference_background_notification"</xliff:g></string>
-    <!-- NOTR -->
-    <string name="preference_energy_optimized_explanation_shown"><xliff:g id="preference">"preference_energy_optimized_explanation_shown"</xliff:g></string>
 
     <!-- ####################################
                      Generics
-- 
GitLab