diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/formatter/FormatterRiskHelper.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/formatter/FormatterRiskHelper.kt index 36bdc637dbefddad93631b3367d0e0d780682539..ee5848aa2d919692f86e34b64effaf46ccb92b32 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/formatter/FormatterRiskHelper.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/formatter/FormatterRiskHelper.kt @@ -281,6 +281,34 @@ fun formatNextUpdate( } } +/** + * Formats the risk card content description of time when diagnosis keys will be updated + * from server again when applicable but appends the word button at the end for screen reader accessibility reasons + * + * @param riskLevelScore + * @param isBackgroundJobEnabled + * @return + */ +fun formatNextUpdateContentDescription( + riskLevelScore: Int?, + isBackgroundJobEnabled: Boolean? +): String { + val appContext = CoronaWarnApplication.getAppContext() + return if (isBackgroundJobEnabled != true) { + "" + } else { + return when (riskLevelScore) { + RiskLevelConstants.UNKNOWN_RISK_INITIAL, + RiskLevelConstants.LOW_LEVEL_RISK, + RiskLevelConstants.INCREASED_RISK -> appContext.getString( + R.string.risk_card_body_next_update + ) + " " + appContext.getString( + R.string.accessibility_button) + else -> "" + } + } +} + /** * Formats the risk details text display for each risk level * diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/formatter/FormatterSettingsHelper.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/formatter/FormatterSettingsHelper.kt index d1decae43d919e5eaf237faa76e648ba6d3fd9c6..2bb50a259c164cda6ddc5923601a38a58c456f44 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/formatter/FormatterSettingsHelper.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/formatter/FormatterSettingsHelper.kt @@ -119,6 +119,34 @@ fun formatTracingDescription(tracing: Boolean, bluetooth: Boolean, connection: B } } +/** + * Format the settings tracing content description text display depending on tracing status + * but appends the word button at the end for screen reader accessibility reasons + * + * @param tracing + * @param bluetooth + * @param connection + * @return String + */ +fun formatTracingContentDescription(tracing: Boolean, bluetooth: Boolean, connection: Boolean): String { + val appContext = CoronaWarnApplication.getAppContext() + return when (tracingStatusHelper(tracing, bluetooth, connection)) { + TracingStatusHelper.CONNECTION -> + appContext.getString(R.string.settings_tracing_body_connection_inactive) + + " " + appContext.getString(R.string.accessibility_button) + TracingStatusHelper.BLUETOOTH -> + appContext.getString(R.string.settings_tracing_body_bluetooth_inactive) + + " " + appContext.getString(R.string.accessibility_button) + TracingStatusHelper.TRACING_ACTIVE -> + appContext.getString(R.string.settings_tracing_body_active) + + " " + appContext.getString(R.string.accessibility_button) + TracingStatusHelper.TRACING_INACTIVE -> + appContext.getString(R.string.settings_tracing_body_inactive) + + " " + appContext.getString(R.string.accessibility_button) + else -> "" + } +} + /** * Formats the tracing body depending on the tracing status and the days since last exposure. * diff --git a/Corona-Warn-App/src/main/res/layout/fragment_main.xml b/Corona-Warn-App/src/main/res/layout/fragment_main.xml index 3dc5df211b1a8b54be0efd0e4160ef5c3aff4f4b..db25a3b62509f578377020b3256282b8d701256b 100644 --- a/Corona-Warn-App/src/main/res/layout/fragment_main.xml +++ b/Corona-Warn-App/src/main/res/layout/fragment_main.xml @@ -102,6 +102,7 @@ android:layout_width="@dimen/match_constraint" android:layout_height="wrap_content" android:focusable="false" + android:contentDescription="@{FormatterSettingsHelper.formatTracingContentDescription(tracingViewModel.isTracingEnabled(), settingsViewModel.isBluetoothEnabled(), settingsViewModel.isConnectionEnabled())}" android:text="@{FormatterSettingsHelper.formatTracingDescription(tracingViewModel.isTracingEnabled(), settingsViewModel.isBluetoothEnabled(), settingsViewModel.isConnectionEnabled())}" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintStart_toStartOf="parent" diff --git a/Corona-Warn-App/src/main/res/layout/include_risk_card.xml b/Corona-Warn-App/src/main/res/layout/include_risk_card.xml index 9c50cbc7028d3ad1b509b4c0f603f4fdc9864e5f..48b1e91d6db96e6eca06ea1431e5e71c6af70792 100644 --- a/Corona-Warn-App/src/main/res/layout/include_risk_card.xml +++ b/Corona-Warn-App/src/main/res/layout/include_risk_card.xml @@ -227,6 +227,7 @@ android:layout_width="@dimen/match_constraint" android:layout_height="wrap_content" android:layout_marginTop="@dimen/spacing_small" + android:contentDescription="@{FormatterRiskHelper.formatNextUpdateContentDescription(tracingViewModel.riskLevel, settingsViewModel.isBackgroundJobEnabled())}" android:text="@{FormatterRiskHelper.formatNextUpdate(tracingViewModel.riskLevel, settingsViewModel.isBackgroundJobEnabled())}" android:textColor="@{FormatterRiskHelper.formatStableTextColor(tracingViewModel.riskLevel)}" app:layout_constraintEnd_toEndOf="parent" 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 6d7e75c434aade804842e7a5db28b769c93c3a22..e9dca21e1bb9eb169e8af36dfa6bd531c74ee907 100644 --- a/Corona-Warn-App/src/main/res/values-de/strings.xml +++ b/Corona-Warn-App/src/main/res/values-de/strings.xml @@ -84,6 +84,8 @@ <string name="accessibility_close">"Schließen"</string> <!-- XACT: menu description for screen readers --> <string name="accessibility_logo">"Corona-Warn-App"</string> + <!-- XACT: button description for screen readers to be appended at the end of content without focusable subcontent that are explored by touch --> + <string name="accessibility_button">"Button"</string> <!-- #################################### Menu 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 56f08e8cc77da722054f0424e747f61cdc1639bb..4ebc2ce02ce8192fc506bff4799bb825cbbababd 100644 --- a/Corona-Warn-App/src/main/res/values-en/strings.xml +++ b/Corona-Warn-App/src/main/res/values-en/strings.xml @@ -84,6 +84,8 @@ <string name="accessibility_close">"Close"</string> <!-- XACT: menu description for screen readers --> <string name="accessibility_logo">"Corona-Warn-App"</string> + <!-- XACT: button description for screen readers to be appended at the end of content without focusable subcontent that are explored by touch --> + <string name="accessibility_button">"Button"</string> <!-- #################################### Menu diff --git a/Corona-Warn-App/src/main/res/values/strings.xml b/Corona-Warn-App/src/main/res/values/strings.xml index 54beed16e1cbaf5365ea27b09f6601517ce22286..78b8238986a2da6448f42e9f2dc67886679a4b21 100644 --- a/Corona-Warn-App/src/main/res/values/strings.xml +++ b/Corona-Warn-App/src/main/res/values/strings.xml @@ -84,6 +84,8 @@ <string name="accessibility_close">"Close"</string> <!-- XACT: menu description for screen readers --> <string name="accessibility_logo">"Corona-Warn-App"</string> + <!-- XACT: button description for screen readers to be appended at the end of content without focusable subcontent that are explored by touch --> + <string name="accessibility_button">"Button"</string> <!-- #################################### Menu diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/formatter/FormatterRiskHelperTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/formatter/FormatterRiskHelperTest.kt index 3d595008ecca58f08d53a07c1244a6871e2250e2..d1830e3b43325c8f0251eb413a68c0223cf4e5f0 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/formatter/FormatterRiskHelperTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/formatter/FormatterRiskHelperTest.kt @@ -168,6 +168,21 @@ class FormatterRiskHelperTest { ) } + private fun formatNextUpdateContentDescriptionBase( + iRiskLevelScore: Int?, + bIsBackgroundJobEnabled: Boolean?, + sValue: String + ) { + every { context.getString(R.string.risk_card_body_next_update) } returns R.string.risk_card_body_next_update.toString() + every { context.getString(R.string.accessibility_button) } returns R.string.accessibility_button.toString() + + val result = + formatNextUpdateContentDescription(riskLevelScore = iRiskLevelScore, isBackgroundJobEnabled = bIsBackgroundJobEnabled) + assertThat( + result, `is`(sValue) + ) + } + private fun formatRiskDetailsRiskLevelBodyBase( iRiskLevelScore: Int?, iDaysSinceLastExposure: Int?, @@ -955,6 +970,71 @@ class FormatterRiskHelperTest { ) } + @Test + fun formatNextUpdateContentDescription() { + formatNextUpdateContentDescriptionBase(iRiskLevelScore = null, bIsBackgroundJobEnabled = null, sValue = "") + formatNextUpdateContentDescriptionBase( + iRiskLevelScore = RiskLevelConstants.INCREASED_RISK, + bIsBackgroundJobEnabled = null, + sValue = "" + ) + formatNextUpdateContentDescriptionBase( + iRiskLevelScore = RiskLevelConstants.UNKNOWN_RISK_OUTDATED_RESULTS, + bIsBackgroundJobEnabled = null, + sValue = "" + ) + formatNextUpdateContentDescriptionBase( + iRiskLevelScore = RiskLevelConstants.NO_CALCULATION_POSSIBLE_TRACING_OFF, + bIsBackgroundJobEnabled = null, + sValue = "" + ) + formatNextUpdateContentDescriptionBase( + iRiskLevelScore = RiskLevelConstants.LOW_LEVEL_RISK, + bIsBackgroundJobEnabled = null, + sValue = "" + ) + formatNextUpdateContentDescriptionBase( + iRiskLevelScore = RiskLevelConstants.UNKNOWN_RISK_INITIAL, + bIsBackgroundJobEnabled = null, + sValue = "" + ) + + formatNextUpdateContentDescriptionBase(iRiskLevelScore = null, bIsBackgroundJobEnabled = true, sValue = "") + formatNextUpdateContentDescriptionBase( + iRiskLevelScore = RiskLevelConstants.INCREASED_RISK, + bIsBackgroundJobEnabled = true, + sValue = context.getString( + R.string.risk_card_body_next_update + ) + " " + context.getString( + R.string.accessibility_button + ) + ) + formatNextUpdateContentDescriptionBase( + iRiskLevelScore = RiskLevelConstants.UNKNOWN_RISK_OUTDATED_RESULTS, + bIsBackgroundJobEnabled = true, + sValue = "" + ) + + formatNextUpdateContentDescriptionBase( + iRiskLevelScore = RiskLevelConstants.LOW_LEVEL_RISK, + bIsBackgroundJobEnabled = true, + sValue = context.getString( + R.string.risk_card_body_next_update + ) + " " + context.getString( + R.string.accessibility_button + ) + ) + formatNextUpdateContentDescriptionBase( + iRiskLevelScore = RiskLevelConstants.UNKNOWN_RISK_INITIAL, + bIsBackgroundJobEnabled = true, + sValue = context.getString( + R.string.risk_card_body_next_update + ) + " " + context.getString( + R.string.accessibility_button + ) + ) + } + @Test fun formatRiskDetailsRiskLevelBody() { formatRiskDetailsRiskLevelBodyBase(iRiskLevelScore = null, iDaysSinceLastExposure = 0, sValue = "") diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/formatter/FormatterSettingsHelperTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/formatter/FormatterSettingsHelperTest.kt index cb6f079b160efae458838538044eae46f909ccd9..79b94264e14699ca7a184f50de07b59ca2df8682 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/formatter/FormatterSettingsHelperTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/util/formatter/FormatterSettingsHelperTest.kt @@ -105,6 +105,29 @@ class FormatterSettingsHelperTest { assertThat(result, `is`((context.getString(iValue)))) } + + private fun formatTracingContentDescriptionBase( + bTracing: Boolean, + bBluetooth: Boolean, + bConnection: Boolean, + sValue: String + ) { + every { context.getString(R.string.settings_tracing_body_bluetooth_inactive) } returns R.string.settings_tracing_body_bluetooth_inactive.toString() + every { context.getString(R.string.settings_tracing_body_connection_inactive) } returns R.string.settings_tracing_body_connection_inactive.toString() + every { context.getString(R.string.settings_tracing_body_active) } returns R.string.settings_tracing_body_active.toString() + every { context.getString(R.string.settings_tracing_body_inactive) } returns R.string.settings_tracing_body_inactive.toString() + every { context.getString(R.string.accessibility_button) } returns R.string.accessibility_button.toString() + + val result = formatTracingContentDescription( + tracing = bTracing, + bluetooth = bBluetooth, + connection = bConnection + ) + assertThat( + result, `is`(sValue) + ) + } + private fun formatNotificationsTitleBase(bValue: Boolean) { val result = formatNotificationsTitle(notifications = bValue) assertThat( @@ -492,6 +515,73 @@ class FormatterSettingsHelperTest { ) } + @Test + fun formatTracingContentDescription() { + // When tracing is true, bluetooth is true, connection is true + formatTracingContentDescriptionBase( + bTracing = true, + bBluetooth = true, + bConnection = true, + sValue = R.string.settings_tracing_body_active.toString() + " " +R.string.accessibility_button.toString() + ) + + // When tracing is false, bluetooth is false, connection is false + formatTracingContentDescriptionBase( + bTracing = false, + bBluetooth = false, + bConnection = false, + sValue = R.string.settings_tracing_body_inactive.toString() + " " +R.string.accessibility_button.toString() + ) + + // When tracing is true, bluetooth is false, connection is false + formatTracingContentDescriptionBase( + bTracing = true, + bBluetooth = false, + bConnection = false, + sValue = R.string.settings_tracing_body_bluetooth_inactive.toString() + " " +R.string.accessibility_button.toString() + ) + + // When tracing is true, bluetooth is true, connection is false + formatTracingContentDescriptionBase( + bTracing = true, + bBluetooth = true, + bConnection = false, + sValue = R.string.settings_tracing_body_connection_inactive.toString() + " " +R.string.accessibility_button.toString() + ) + + // When tracing is false, bluetooth is true, connection is false + formatTracingContentDescriptionBase( + bTracing = false, + bBluetooth = true, + bConnection = false, + sValue = R.string.settings_tracing_body_inactive.toString() + " " +R.string.accessibility_button.toString() + ) + + // When tracing is false, bluetooth is true, connection is true + formatTracingContentDescriptionBase( + bTracing = false, + bBluetooth = true, + bConnection = true, + sValue = R.string.settings_tracing_body_inactive.toString() + " " +R.string.accessibility_button.toString() + ) + + // When tracing is true, bluetooth is false, connection is true + formatTracingContentDescriptionBase( + bTracing = true, + bBluetooth = false, + bConnection = true, + sValue = R.string.settings_tracing_body_bluetooth_inactive.toString() + " " +R.string.accessibility_button.toString() + ) + + // When tracing is false, bluetooth is false, connection is true + formatTracingContentDescriptionBase( + bTracing = false, + bBluetooth = false, + bConnection = true, + sValue = R.string.settings_tracing_body_inactive.toString() + " " +R.string.accessibility_button.toString() + ) + } + @Test fun formatNotificationsTitle() { // When status true