From 8296d1fe1c9024a10b34dfc275798b994ad29e39 Mon Sep 17 00:00:00 2001
From: fynngodau <fynngodau@mailbox.org>
Date: Tue, 4 May 2021 11:27:03 +0200
Subject: [PATCH] Support Android 5 (COMMUNITY) (#2955)

* Android 5 support

* Hide background priority settings on Android 5

Since these settings make no sense there, we are hiding them below Android
Marshmellow.

* Use AppCompat Toolbar

This makes the three-dot menu visible on Android 5

* Fix background color of behavior icons on Android 5

* Fix TAN digits for Android 5

This is a very weird way of doing it, but since Android 5 doesn't
support the height attribute, it appears to be the best solution.
Via https://stackoverflow.com/a/19239478.

* Fix cardTracing style on Android 5

Since this backgroundTint was not applied, simply use the card_dark
drawable that already has the color we want.

* Remove splash screen on API < 23

Splash screens on Android 5 are very broken, as the images on the splash
screen are streched to fit the screen width. Therefore, the splash
screen can only be shown on API >= 23.

* Remove unused import to fix lint

* Fix tests

* Undo change to min sdk version

This partially reverts commit 2edced1c532ff235fd6d09c8cf19a4a10b491d51.

* Small improvements to compat changes

* Change BehaviorInfoRow to use ViewCompat call except if on 5.0

* Improve code readability

* Move restore non-hacky TAN input drawables for Android >= 6

* Fix drawable files that were placed the wrong way round

* Add comments to Android 5 TAN digit assets

As suggested by @vaubaehn

* Remove unused imports

* Use BuildVersionWrap again in NetworkStateProvider

This allows mocking the SDK version in tests

* Update splash screen

* Compat for new code

* Fix typo

* Don't migrate encrypted shared prefs on API < 23

Co-authored-by: harambasicluka <64483219+harambasicluka@users.noreply.github.com>
Co-authored-by: Mohamed <mohamed.metwalli@sap.com>
Co-authored-by: Matthias Urhahn <matthias.urhahn@sap.com>
---
 .../ui/ContactDiaryTestFragment.kt            |  5 +-
 Corona-Warn-App/src/main/AndroidManifest.xml  |  2 +-
 .../coronawarnapp/CoronaWarnApplication.kt    |  8 ++-
 .../bugreporting/ui/ErrorDialog.kt            |  3 +-
 .../tabs/location/DiaryLocationViewHolder.kt  |  5 +-
 .../details/items/behavior/BehaviorInfoRow.kt | 11 +++-
 .../ui/calendar/CalendarWeekDayView.kt        |  5 +-
 .../coronawarnapp/ui/main/home/HomeMenu.kt    |  2 +-
 .../settings/start/SettingsBackgroundState.kt |  8 +++
 .../ui/submission/tan/TanInput.kt             |  5 +-
 .../coronawarnapp/util/ConnectivityHelper.kt  | 15 ++++-
 .../de/rki/coronawarnapp/util/DialogHelper.kt |  3 +-
 .../util/device/PowerManagement.kt            | 16 ++---
 .../util/di/ApplicationComponent.kt           |  3 +-
 .../util/network/NetworkStateProvider.kt      | 65 ++++++++++++-------
 .../main/res/drawable-v23/tan_input_digit.xml | 18 +++++
 .../drawable-v23/tan_input_digit_error.xml    | 18 +++++
 .../src/main/res/drawable/splash_screen.xml   |  8 ++-
 .../src/main/res/drawable/tan_input_digit.xml | 19 ++++--
 .../res/drawable/tan_input_digit_error.xml    | 20 ++++--
 .../src/main/res/layout/fragment_settings.xml |  1 +
 .../main/res/layout/home_fragment_layout.xml  |  4 +-
 .../src/main/res/values/styles.xml            |  3 +-
 .../coronawarnapp/risk/RiskLevelTaskTest.kt   |  7 ++
 .../util/network/NetworkStateProviderTest.kt  |  2 +-
 25 files changed, 188 insertions(+), 68 deletions(-)
 create mode 100644 Corona-Warn-App/src/main/res/drawable-v23/tan_input_digit.xml
 create mode 100644 Corona-Warn-App/src/main/res/drawable-v23/tan_input_digit_error.xml

diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/contactdiary/ui/ContactDiaryTestFragment.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/contactdiary/ui/ContactDiaryTestFragment.kt
index 1fa7e54d4..3cf44a65b 100644
--- a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/contactdiary/ui/ContactDiaryTestFragment.kt
+++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/contactdiary/ui/ContactDiaryTestFragment.kt
@@ -3,6 +3,7 @@ package de.rki.coronawarnapp.test.contactdiary.ui
 import android.annotation.SuppressLint
 import android.os.Bundle
 import android.view.View
+import androidx.core.widget.TextViewCompat
 import androidx.fragment.app.Fragment
 import de.rki.coronawarnapp.R
 import de.rki.coronawarnapp.databinding.FragmentTestContactDiaryBinding
@@ -84,10 +85,10 @@ class ContactDiaryTestFragment :
             text = duration.toContactDiaryFormat()
             if (duration.millis == 0L) {
                 setBackgroundResource(R.drawable.contact_diary_duration_background_default)
-                setTextAppearance(R.style.bodyNeutral)
+                TextViewCompat.setTextAppearance(this, R.style.bodyNeutral)
             } else {
                 setBackgroundResource(R.drawable.contact_diary_duration_background_selected)
-                setTextAppearance(R.style.body1)
+                TextViewCompat.setTextAppearance(this, R.style.body1)
             }
         }
     }
diff --git a/Corona-Warn-App/src/main/AndroidManifest.xml b/Corona-Warn-App/src/main/AndroidManifest.xml
index 2fc4b03cb..20dd21fbd 100644
--- a/Corona-Warn-App/src/main/AndroidManifest.xml
+++ b/Corona-Warn-App/src/main/AndroidManifest.xml
@@ -4,7 +4,7 @@
     package="de.rki.coronawarnapp"
     tools:ignore="LockedOrientationActivity">
 
-    <uses-sdk tools:overrideLibrary="com.google.zxing.client.android" />
+    <uses-sdk tools:overrideLibrary="com.google.zxing.client.android,androidx.security" />
 
     <uses-feature
         android:name="android.hardware.bluetooth_le"
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/CoronaWarnApplication.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/CoronaWarnApplication.kt
index b0c270e62..735cee276 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/CoronaWarnApplication.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/CoronaWarnApplication.kt
@@ -34,11 +34,13 @@ import de.rki.coronawarnapp.risk.execution.ExposureWindowRiskWorkScheduler
 import de.rki.coronawarnapp.storage.OnboardingSettings
 import de.rki.coronawarnapp.submission.auto.AutoSubmission
 import de.rki.coronawarnapp.task.TaskController
+import de.rki.coronawarnapp.util.BuildVersionWrap
 import de.rki.coronawarnapp.util.CWADebug
 import de.rki.coronawarnapp.util.WatchdogService
 import de.rki.coronawarnapp.util.device.ForegroundState
 import de.rki.coronawarnapp.util.di.AppInjector
 import de.rki.coronawarnapp.util.di.ApplicationComponent
+import de.rki.coronawarnapp.util.hasAPILevel
 import kotlinx.coroutines.GlobalScope
 import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.onEach
@@ -87,8 +89,10 @@ class CoronaWarnApplication : Application(), HasAndroidInjector {
         CWADebug.init(this)
 
         AppInjector.init(this).let { compPreview ->
-            Timber.v("Calling EncryptedPreferencesMigration.doMigration()")
-            compPreview.encryptedMigration.doMigration()
+            if (BuildVersionWrap.hasAPILevel(23)) {
+                Timber.v("Calling EncryptedPreferencesMigration.doMigration()")
+                compPreview.encryptedMigration.get().doMigration()
+            }
 
             CWADebug.initAfterInjection(compPreview)
 
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/ui/ErrorDialog.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/ui/ErrorDialog.kt
index 49e16cef4..c4b4af463 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/ui/ErrorDialog.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/ui/ErrorDialog.kt
@@ -6,6 +6,7 @@ import android.text.method.LinkMovementMethod
 import android.text.util.Linkify
 import android.widget.TextView
 import androidx.appcompat.app.AlertDialog
+import androidx.core.widget.TextViewCompat
 import com.google.android.material.dialog.MaterialAlertDialogBuilder
 import de.rki.coronawarnapp.R
 import de.rki.coronawarnapp.util.ContextExtensions.getColorStateListCompat
@@ -34,7 +35,7 @@ private fun MaterialAlertDialogBuilder.setMessageView(
             paddingStartEnd,
             paddingLeftRight
         )
-        setTextAppearance(R.style.body1)
+        TextViewCompat.setTextAppearance(this, R.style.body1)
         setLinkTextColor(context.getColorStateListCompat(R.color.button_primary))
         setTextIsSelectable(!textHasLinks)
     }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/tabs/location/DiaryLocationViewHolder.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/tabs/location/DiaryLocationViewHolder.kt
index 01cc23cd0..ee2d4f701 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/tabs/location/DiaryLocationViewHolder.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ui/day/tabs/location/DiaryLocationViewHolder.kt
@@ -2,6 +2,7 @@ package de.rki.coronawarnapp.contactdiary.ui.day.tabs.location
 
 import android.view.ViewGroup
 import android.view.accessibility.AccessibilityEvent
+import androidx.core.widget.TextViewCompat
 import de.rki.coronawarnapp.R
 import de.rki.coronawarnapp.contactdiary.util.hideKeyboard
 import de.rki.coronawarnapp.contactdiary.util.setClickLabel
@@ -48,10 +49,10 @@ class DiaryLocationViewHolder(
             if (duration == null || duration.millis == 0L) {
                 text = context.getString(R.string.duration_dialog_default_value)
                 setBackgroundResource(R.drawable.contact_diary_duration_background_default)
-                setTextAppearance(R.style.bodyNeutral)
+                TextViewCompat.setTextAppearance(this, R.style.bodyNeutral)
             } else {
                 setBackgroundResource(R.drawable.contact_diary_duration_background_selected)
-                setTextAppearance(R.style.body1)
+                TextViewCompat.setTextAppearance(this, R.style.body1)
             }
         }
 
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/tracing/ui/details/items/behavior/BehaviorInfoRow.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/tracing/ui/details/items/behavior/BehaviorInfoRow.kt
index 9c7a0c565..e544d8456 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/tracing/ui/details/items/behavior/BehaviorInfoRow.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/tracing/ui/details/items/behavior/BehaviorInfoRow.kt
@@ -2,6 +2,8 @@ package de.rki.coronawarnapp.tracing.ui.details.items.behavior
 
 import android.content.Context
 import android.content.res.ColorStateList
+import android.graphics.PorterDuff
+import android.os.Build
 import android.util.AttributeSet
 import android.view.LayoutInflater
 import android.view.View
@@ -14,6 +16,8 @@ import androidx.core.content.withStyledAttributes
 import androidx.core.view.ViewCompat
 import androidx.core.widget.ImageViewCompat
 import de.rki.coronawarnapp.R
+import de.rki.coronawarnapp.util.BuildVersionWrap
+import de.rki.coronawarnapp.util.hasAPILevel
 import de.rki.coronawarnapp.util.setUrl
 
 class BehaviorInfoRow @JvmOverloads constructor(
@@ -61,7 +65,12 @@ class BehaviorInfoRow @JvmOverloads constructor(
     }
 
     fun setBackgroundTint(@ColorInt color: Int) {
-        ViewCompat.setBackgroundTintList(iconBackground, ColorStateList.valueOf(color))
+        when {
+            BuildVersionWrap.hasAPILevel(Build.VERSION_CODES.LOLLIPOP_MR1) ->
+                ViewCompat.setBackgroundTintList(iconBackground, ColorStateList.valueOf(color))
+            else ->
+                iconBackground.background.setColorFilter(color, PorterDuff.Mode.SRC_OVER)
+        }
     }
 
     fun setForegroundTint(@ColorInt color: Int) {
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/calendar/CalendarWeekDayView.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/calendar/CalendarWeekDayView.kt
index 52ff504e3..2b352a1f6 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/calendar/CalendarWeekDayView.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/calendar/CalendarWeekDayView.kt
@@ -5,6 +5,7 @@ import android.util.AttributeSet
 import android.view.LayoutInflater
 import android.widget.LinearLayout
 import android.widget.TextView
+import androidx.core.widget.TextViewCompat
 import de.rki.coronawarnapp.R
 
 /**
@@ -43,9 +44,9 @@ class CalendarWeekDayView @JvmOverloads constructor(
         textView.text = text
 
         if (isSelected) {
-            textView.setTextAppearance(R.style.calendarWeekDaySelected)
+            TextViewCompat.setTextAppearance(textView, R.style.calendarWeekDaySelected)
         } else {
-            textView.setTextAppearance(R.style.calendarWeekDayNormal)
+            TextViewCompat.setTextAppearance(textView, R.style.calendarWeekDayNormal)
         }
     }
 }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/HomeMenu.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/HomeMenu.kt
index 306b9598a..4189f6bd9 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/HomeMenu.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/home/HomeMenu.kt
@@ -1,7 +1,7 @@
 package de.rki.coronawarnapp.ui.main.home
 
 import android.view.MenuItem.SHOW_AS_ACTION_ALWAYS
-import android.widget.Toolbar
+import androidx.appcompat.widget.Toolbar
 import androidx.navigation.NavController
 import androidx.navigation.fragment.findNavController
 import de.rki.coronawarnapp.R
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/settings/start/SettingsBackgroundState.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/settings/start/SettingsBackgroundState.kt
index 470cf3234..4217b4972 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/settings/start/SettingsBackgroundState.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/settings/start/SettingsBackgroundState.kt
@@ -2,10 +2,13 @@ package de.rki.coronawarnapp.ui.settings.start
 
 import android.content.Context
 import android.graphics.drawable.Drawable
+import android.os.Build
 import androidx.annotation.ColorInt
 import de.rki.coronawarnapp.R
+import de.rki.coronawarnapp.util.BuildVersionWrap
 import de.rki.coronawarnapp.util.ContextExtensions.getColorCompat
 import de.rki.coronawarnapp.util.ContextExtensions.getDrawableCompat
+import de.rki.coronawarnapp.util.hasAPILevel
 
 data class SettingsBackgroundState(
     val isEnabled: Boolean
@@ -34,4 +37,9 @@ data class SettingsBackgroundState(
     fun getBackgroundPriorityText(c: Context): String = c.getString(
         if (isEnabled) R.string.settings_on else R.string.settings_off
     )
+
+    /**
+     * Whether the "background priority" row should be visible in the settings
+     */
+    fun showBackgroundPrioritySettings(): Boolean = BuildVersionWrap.hasAPILevel(Build.VERSION_CODES.M)
 }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/tan/TanInput.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/tan/TanInput.kt
index 70ceed8db..f71c5e179 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/tan/TanInput.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/tan/TanInput.kt
@@ -14,6 +14,7 @@ import androidx.annotation.DimenRes
 import androidx.core.view.children
 import androidx.core.widget.doOnTextChanged
 import de.rki.coronawarnapp.R
+import de.rki.coronawarnapp.util.ContextExtensions.getColorCompat
 import de.rki.coronawarnapp.util.getDrawableCompat
 import java.util.Locale
 import kotlin.math.max
@@ -107,9 +108,9 @@ class TanInput(context: Context, attrs: AttributeSet) : ViewGroup(context, attrs
 
         tanDigit.setTextColor(
             if (Tan.isTanCharacterValid(text))
-                resources.getColor(R.color.colorTextPrimary1, null)
+                context.getColorCompat(R.color.colorTextPrimary1)
             else
-                resources.getColor(R.color.colorTextSemanticRed, null)
+                context.getColorCompat(R.color.colorTextSemanticRed)
         )
     }
 
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 246ca1e5a..f169b9c7b 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
@@ -5,6 +5,7 @@ import android.net.ConnectivityManager
 import android.net.Network
 import android.net.NetworkCapabilities
 import android.net.NetworkRequest
+import android.os.Build
 import de.rki.coronawarnapp.exception.ExceptionCategory
 import de.rki.coronawarnapp.exception.reporting.report
 
@@ -76,9 +77,17 @@ object ConnectivityHelper {
      */
     fun isNetworkEnabled(context: Context): Boolean {
         val manager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
-        val activeNetwork: Network? = manager.activeNetwork
-        val caps: NetworkCapabilities? = manager.getNetworkCapabilities(activeNetwork)
-        return caps?.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED) ?: false
+        return when {
+            Build.VERSION.SDK_INT >= Build.VERSION_CODES.M -> {
+                val activeNetwork = manager.activeNetwork
+                val caps: NetworkCapabilities? = manager.getNetworkCapabilities(activeNetwork)
+                caps?.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED) ?: false
+            }
+            else -> {
+                val activeNetworkInfo = manager.activeNetworkInfo
+                activeNetworkInfo != null && activeNetworkInfo.isConnected
+            }
+        }
     }
 
     /**
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/DialogHelper.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/DialogHelper.kt
index dedb9a57f..9688f3585 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/DialogHelper.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/DialogHelper.kt
@@ -6,6 +6,7 @@ import android.text.method.LinkMovementMethod
 import android.text.util.Linkify
 import android.widget.TextView
 import androidx.appcompat.app.AlertDialog
+import androidx.core.widget.TextViewCompat
 import de.rki.coronawarnapp.R
 import de.rki.coronawarnapp.util.ContextExtensions.getColorStateListCompat
 import java.util.regex.Pattern
@@ -111,7 +112,7 @@ object DialogHelper {
         textView.linksClickable = true
         textView.movementMethod = LinkMovementMethod.getInstance()
         textView.setPadding(paddingStartEnd, paddingLeftRight, paddingStartEnd, paddingLeftRight)
-        textView.setTextAppearance(R.style.body1)
+        TextViewCompat.setTextAppearance(textView, R.style.body1)
         textView.setLinkTextColor(context.getColorStateListCompat(R.color.button_primary))
         if (isTextSelectable) textView.setTextIsSelectable(true)
         return textView
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/device/PowerManagement.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/device/PowerManagement.kt
index f022f72dd..294f10ec0 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/device/PowerManagement.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/device/PowerManagement.kt
@@ -2,9 +2,10 @@ package de.rki.coronawarnapp.util.device
 
 import android.content.Context
 import android.content.Intent
-import android.net.Uri
+import android.os.Build
 import android.os.PowerManager
 import android.provider.Settings
+import androidx.annotation.RequiresApi
 import androidx.core.content.getSystemService
 import de.rki.coronawarnapp.util.di.AppContext
 import javax.inject.Inject
@@ -18,14 +19,13 @@ class PowerManagement @Inject constructor(
     private val powerManager by lazy { context.getSystemService<PowerManager>()!! }
 
     val isIgnoringBatteryOptimizations
-        get() = powerManager.isIgnoringBatteryOptimizations(context.packageName)
+        get() = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+            powerManager.isIgnoringBatteryOptimizations(context.packageName)
+        } else {
+            true
+        }
 
+    @RequiresApi(Build.VERSION_CODES.M)
     val toBatteryOptimizationSettingsIntent =
         Intent(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS)
-
-    val disableBatteryOptimizationsIntent =
-        Intent(
-            Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS,
-            Uri.parse("package:${context.packageName}")
-        )
 }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/di/ApplicationComponent.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/di/ApplicationComponent.kt
index 574ed5dbc..1728ab937 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/di/ApplicationComponent.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/di/ApplicationComponent.kt
@@ -2,6 +2,7 @@ package de.rki.coronawarnapp.util.di
 
 import dagger.BindsInstance
 import dagger.Component
+import dagger.Lazy
 import dagger.android.AndroidInjector
 import dagger.android.support.AndroidSupportInjectionModule
 import de.rki.coronawarnapp.CoronaWarnApplication
@@ -102,7 +103,7 @@ interface ApplicationComponent : AndroidInjector<CoronaWarnApplication> {
 
     fun inject(logger: DebugLogger)
 
-    val encryptedMigration: EncryptedPreferencesMigration
+    val encryptedMigration: Lazy<EncryptedPreferencesMigration>
 
     @Component.Factory
     interface Factory {
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/network/NetworkStateProvider.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/network/NetworkStateProvider.kt
index 7f06ba7a3..6a550115d 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/network/NetworkStateProvider.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/network/NetworkStateProvider.kt
@@ -1,5 +1,6 @@
 package de.rki.coronawarnapp.util.network
 
+import android.annotation.SuppressLint
 import android.content.Context
 import android.net.ConnectivityManager
 import android.net.LinkProperties
@@ -8,6 +9,8 @@ import android.net.NetworkCapabilities
 import android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET
 import android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED
 import android.os.Build
+import androidx.annotation.RequiresApi
+import androidx.core.net.ConnectivityManagerCompat
 import de.rki.coronawarnapp.storage.TestSettings
 import de.rki.coronawarnapp.util.BuildVersionWrap
 import de.rki.coronawarnapp.util.coroutine.AppScope
@@ -90,34 +93,50 @@ class NetworkStateProvider @Inject constructor(
         )
 
     private val currentState: State
-        get() = manager.activeNetwork.let { network ->
-            State(
-                activeNetwork = network,
-                capabilities = network?.let {
-                    try {
-                        manager.getNetworkCapabilities(it)
-                    } catch (e: SecurityException) {
-                        Timber.tag(TAG).e(e, "Failed to determine network capabilities.")
-                        null
-                    }
-                },
-                linkProperties = network?.let {
-                    try {
-                        manager.getLinkProperties(it)
-                    } catch (e: Exception) {
-                        Timber.tag(TAG).e(e, "Failed to determine link properties.")
-                        null
-                    }
-                },
-                isFakeMeteredConnection = testSettings.fakeMeteredConnection.value
-            )
+        @SuppressLint("NewApi")
+        get() = when {
+            BuildVersionWrap.hasAPILevel(Build.VERSION_CODES.M) -> api23NetworkState()
+            else -> {
+                // Most state information is not available
+                State(
+                    activeNetwork = null,
+                    capabilities = null,
+                    linkProperties = null,
+                    assumeMeteredConnection = testSettings.fakeMeteredConnection.value ||
+                        ConnectivityManagerCompat.isActiveNetworkMetered(manager)
+                )
+            }
         }
 
+    @RequiresApi(Build.VERSION_CODES.M)
+    private fun api23NetworkState() = manager.activeNetwork.let { network ->
+        State(
+            activeNetwork = network,
+            capabilities = network?.let {
+                try {
+                    manager.getNetworkCapabilities(it)
+                } catch (e: SecurityException) {
+                    Timber.tag(TAG).e(e, "Failed to determine network capabilities.")
+                    null
+                }
+            },
+            linkProperties = network?.let {
+                try {
+                    manager.getLinkProperties(it)
+                } catch (e: Exception) {
+                    Timber.tag(TAG).e(e, "Failed to determine link properties.")
+                    null
+                }
+            },
+            assumeMeteredConnection = testSettings.fakeMeteredConnection.value
+        )
+    }
+
     data class State(
         val activeNetwork: Network?,
         val capabilities: NetworkCapabilities?,
         val linkProperties: LinkProperties?,
-        private val isFakeMeteredConnection: Boolean = false
+        private val assumeMeteredConnection: Boolean = false
     ) {
         val isMeteredConnection: Boolean
             get() {
@@ -126,7 +145,7 @@ class NetworkStateProvider @Inject constructor(
                 } else {
                     capabilities?.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) ?: false
                 }
-                return isFakeMeteredConnection || !unMetered
+                return assumeMeteredConnection || !unMetered
             }
     }
 
diff --git a/Corona-Warn-App/src/main/res/drawable-v23/tan_input_digit.xml b/Corona-Warn-App/src/main/res/drawable-v23/tan_input_digit.xml
new file mode 100644
index 000000000..f748bc904
--- /dev/null
+++ b/Corona-Warn-App/src/main/res/drawable-v23/tan_input_digit.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item>
+        <shape android:shape="rectangle">
+            <corners android:radius="@dimen/submission_tan_input_digit_radius" />
+            <solid android:color="@color/colorSurface2" />
+        </shape>
+    </item>
+    <item
+        android:height="@dimen/submission_tan_input_digit_stroke"
+        android:gravity="bottom">
+        <shape android:shape="rectangle">
+            <corners android:bottomLeftRadius="@dimen/submission_tan_input_digit_radius" />
+            <corners android:bottomRightRadius="@dimen/submission_tan_input_digit_radius" />
+            <solid android:color="@color/colorTextSemanticNeutral" />
+        </shape>
+    </item>
+</layer-list>
\ No newline at end of file
diff --git a/Corona-Warn-App/src/main/res/drawable-v23/tan_input_digit_error.xml b/Corona-Warn-App/src/main/res/drawable-v23/tan_input_digit_error.xml
new file mode 100644
index 000000000..8e293e04f
--- /dev/null
+++ b/Corona-Warn-App/src/main/res/drawable-v23/tan_input_digit_error.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item>
+        <shape android:shape="rectangle">
+            <corners android:radius="@dimen/submission_tan_input_digit_radius" />
+            <solid android:color="@color/colorSurface2" />
+        </shape>
+    </item>
+    <item
+        android:height="@dimen/submission_tan_input_digit_stroke"
+        android:gravity="bottom">
+        <shape android:shape="rectangle">
+            <corners android:bottomLeftRadius="@dimen/submission_tan_input_digit_radius" />
+            <corners android:bottomRightRadius="@dimen/submission_tan_input_digit_radius" />
+            <solid android:color="@color/colorTextSemanticRed" />
+        </shape>
+    </item>
+</layer-list>
diff --git a/Corona-Warn-App/src/main/res/drawable/splash_screen.xml b/Corona-Warn-App/src/main/res/drawable/splash_screen.xml
index 78d8273a0..f3cffa04d 100644
--- a/Corona-Warn-App/src/main/res/drawable/splash_screen.xml
+++ b/Corona-Warn-App/src/main/res/drawable/splash_screen.xml
@@ -5,8 +5,10 @@
     <item android:drawable="@color/colorBackground" />
 
     <!-- logo -->
-    <item
-        android:drawable="@drawable/ic_splash_logo_round"
-        android:gravity="center" />
+    <item>
+        <bitmap
+            android:gravity="center"
+            android:src="@drawable/ic_splash_logo_round" />
+    </item>
 
 </layer-list>
\ No newline at end of file
diff --git a/Corona-Warn-App/src/main/res/drawable/tan_input_digit.xml b/Corona-Warn-App/src/main/res/drawable/tan_input_digit.xml
index f748bc904..8b469ff0b 100644
--- a/Corona-Warn-App/src/main/res/drawable/tan_input_digit.xml
+++ b/Corona-Warn-App/src/main/res/drawable/tan_input_digit.xml
@@ -1,5 +1,12 @@
 <?xml version="1.0" encoding="utf-8"?>
 <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <!--
+        This asset is only used below Android 6. These Android versions
+        do not support the `android:height` and `android:width` attributes,
+        making tricks necessary.
+    -->
+
     <item>
         <shape android:shape="rectangle">
             <corners android:radius="@dimen/submission_tan_input_digit_radius" />
@@ -7,12 +14,14 @@
         </shape>
     </item>
     <item
-        android:height="@dimen/submission_tan_input_digit_stroke"
-        android:gravity="bottom">
+        android:top="-4dp"
+        android:right="-4dp"
+        android:left="-4dp">
         <shape android:shape="rectangle">
-            <corners android:bottomLeftRadius="@dimen/submission_tan_input_digit_radius" />
-            <corners android:bottomRightRadius="@dimen/submission_tan_input_digit_radius" />
-            <solid android:color="@color/colorTextSemanticNeutral" />
+            <stroke
+                android:width="@dimen/submission_tan_input_digit_stroke"
+                android:color="@color/colorTextSemanticNeutral"
+                />
         </shape>
     </item>
 </layer-list>
\ No newline at end of file
diff --git a/Corona-Warn-App/src/main/res/drawable/tan_input_digit_error.xml b/Corona-Warn-App/src/main/res/drawable/tan_input_digit_error.xml
index 8e293e04f..93f55158e 100644
--- a/Corona-Warn-App/src/main/res/drawable/tan_input_digit_error.xml
+++ b/Corona-Warn-App/src/main/res/drawable/tan_input_digit_error.xml
@@ -1,5 +1,13 @@
 <?xml version="1.0" encoding="utf-8"?>
 <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <!--
+        This asset is only used below Android 6. These Android versions
+        do not support the `android:height` and `android:width` attributes,
+        making tricks necessary.
+    -->
+
+
     <item>
         <shape android:shape="rectangle">
             <corners android:radius="@dimen/submission_tan_input_digit_radius" />
@@ -7,12 +15,14 @@
         </shape>
     </item>
     <item
-        android:height="@dimen/submission_tan_input_digit_stroke"
-        android:gravity="bottom">
+        android:top="-4dp"
+        android:right="-4dp"
+        android:left="-4dp">
         <shape android:shape="rectangle">
-            <corners android:bottomLeftRadius="@dimen/submission_tan_input_digit_radius" />
-            <corners android:bottomRightRadius="@dimen/submission_tan_input_digit_radius" />
-            <solid android:color="@color/colorTextSemanticRed" />
+            <stroke
+                android:width="@dimen/submission_tan_input_digit_stroke"
+                android:color="@color/colorTextSemanticRed"
+                />
         </shape>
     </item>
 </layer-list>
diff --git a/Corona-Warn-App/src/main/res/layout/fragment_settings.xml b/Corona-Warn-App/src/main/res/layout/fragment_settings.xml
index 48388cf27..ff0797231 100644
--- a/Corona-Warn-App/src/main/res/layout/fragment_settings.xml
+++ b/Corona-Warn-App/src/main/res/layout/fragment_settings.xml
@@ -91,6 +91,7 @@
                     layout="@layout/include_setting_row"
                     android:layout_width="0dp"
                     android:layout_height="wrap_content"
+                    app:gone="@{!backgroundState.showBackgroundPrioritySettings()}"
                     app:body="@{@string/settings_background_priority_body_description}"
                     app:color="@{backgroundState.getBackgroundPriorityIconColor(context)}"
                     app:icon="@{backgroundState.getBackgroundPriorityIcon(context)}"
diff --git a/Corona-Warn-App/src/main/res/layout/home_fragment_layout.xml b/Corona-Warn-App/src/main/res/layout/home_fragment_layout.xml
index 683de0e8d..79b703795 100644
--- a/Corona-Warn-App/src/main/res/layout/home_fragment_layout.xml
+++ b/Corona-Warn-App/src/main/res/layout/home_fragment_layout.xml
@@ -18,7 +18,7 @@
         android:orientation="vertical"
         tools:context=".ui.main.MainActivity">
 
-        <Toolbar
+        <com.google.android.material.appbar.MaterialToolbar
             android:id="@+id/toolbar"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
@@ -34,7 +34,7 @@
                 app:srcCompat="@drawable/ic_main_header"
                 bind:cwaContentDescription="@{@string/accessibility_logo}"
                 tools:ignore="ContentDescription" />
-        </Toolbar>
+        </com.google.android.material.appbar.MaterialToolbar>
 
         <androidx.coordinatorlayout.widget.CoordinatorLayout
             android:layout_width="match_parent"
diff --git a/Corona-Warn-App/src/main/res/values/styles.xml b/Corona-Warn-App/src/main/res/values/styles.xml
index bc944522a..dbdaf8ec6 100644
--- a/Corona-Warn-App/src/main/res/values/styles.xml
+++ b/Corona-Warn-App/src/main/res/values/styles.xml
@@ -251,8 +251,7 @@
 
     <style name="cardTracing">
         <item name="android:padding">@dimen/card_padding</item>
-        <item name="android:background">@drawable/card</item>
-        <item name="android:backgroundTint">@color/colorSurface2</item>
+        <item name="android:background">@drawable/card_dark</item>
     </style>
 
     <style name="selectionButton" parent="@style/Widget.AppCompat.Button.Borderless">
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/risk/RiskLevelTaskTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/risk/RiskLevelTaskTest.kt
index b9f84a180..0c6f3fce2 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/risk/RiskLevelTaskTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/risk/RiskLevelTaskTest.kt
@@ -4,6 +4,7 @@ import android.content.Context
 import android.net.ConnectivityManager
 import android.net.Network
 import android.net.NetworkCapabilities
+import android.net.NetworkInfo
 import de.rki.coronawarnapp.appconfig.AppConfigProvider
 import de.rki.coronawarnapp.appconfig.ConfigData
 import de.rki.coronawarnapp.coronatest.CoronaTestRepository
@@ -83,6 +84,9 @@ class RiskLevelTaskTest : BaseTest() {
                     every { hasCapability(any()) } returns true
                 }
             }
+            every { activeNetworkInfo } returns mockk<NetworkInfo>().apply {
+                every { isConnected } returns true
+            }
         }
 
         every { enfClient.isTracingEnabled } returns flowOf(true)
@@ -138,6 +142,9 @@ class RiskLevelTaskTest : BaseTest() {
                     every { hasCapability(any()) } returns false
                 }
             }
+            every { activeNetworkInfo } returns mockk<NetworkInfo>().apply {
+                every { isConnected } returns false
+            }
         }
 
         createTask().run(arguments) shouldBe EwRiskLevelTaskResult(
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/network/NetworkStateProviderTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/network/NetworkStateProviderTest.kt
index 6c48eeb1e..76c94e508 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/network/NetworkStateProviderTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/network/NetworkStateProviderTest.kt
@@ -198,7 +198,7 @@ class NetworkStateProviderTest : BaseTest() {
     }
 
     @Test
-    fun `metered connection state can be overriden via test settings`() = runBlockingTest2(ignoreActive = true) {
+    fun `metered connection state can be overridden via test settings`() = runBlockingTest2(ignoreActive = true) {
         every { testSettings.fakeMeteredConnection } returns mockFlowPreference(true)
         val instance = createInstance(this)
 
-- 
GitLab