From 96ad91fb7982f0a1a30b000d03964d5ec811e1a1 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Thu, 25 Mar 2021 08:28:47 +0530 Subject: [PATCH] Fix #2631: A11y Options Language screen (#2784) * added labels for options language screen * a11y update * Added Tests * fixed spacing issues * fix * unused imports deleted * Added tests for labels * Fixed formatting issues * Tests updated * Removed unused imports * merged develop * Update app/src/sharedTest/java/org/oppia/android/app/options/AudioLanguageActivityTest.kt Co-authored-by: Ben Henning Co-authored-by: Ben Henning --- app/src/main/AndroidManifest.xml | 6 +- .../res/layout-land/app_language_fragment.xml | 2 +- .../layout-land/audio_language_fragment.xml | 2 +- .../main/res/layout-land/language_items.xml | 3 + .../main/res/layout/app_language_fragment.xml | 2 +- .../res/layout/audio_language_fragment.xml | 2 +- app/src/main/res/layout/language_items.xml | 3 + app/src/main/res/values/strings.xml | 4 +- .../app/options/AppLanguageActivityTest.kt | 154 ++++++++++++++++++ .../app/options/AudioLanguageActivityTest.kt | 153 +++++++++++++++++ 10 files changed, 323 insertions(+), 8 deletions(-) create mode 100644 app/src/sharedTest/java/org/oppia/android/app/options/AppLanguageActivityTest.kt create mode 100644 app/src/sharedTest/java/org/oppia/android/app/options/AudioLanguageActivityTest.kt diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index a2aef32494b..9ec6b6a6672 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -56,10 +56,12 @@ android:theme="@style/OppiaThemeWithoutActionBar" /> + android:theme="@style/OppiaThemeWithoutActionBar" + android:label="@string/app_language_activity_title" /> + android:theme="@style/OppiaThemeWithoutActionBar" + android:label="@string/audio_language_activity_title" /> diff --git a/app/src/main/res/layout-land/app_language_fragment.xml b/app/src/main/res/layout-land/app_language_fragment.xml index 96e83dc6714..e6b84ead9e0 100644 --- a/app/src/main/res/layout-land/app_language_fragment.xml +++ b/app/src/main/res/layout-land/app_language_fragment.xml @@ -31,7 +31,7 @@ android:minHeight="?attr/actionBarSize" app:navigationContentDescription="@string/navigate_up" app:navigationIcon="?attr/homeAsUpIndicator" - app:title="@string/title_app_language" + app:title="@string/app_language_activity_title" app:titleTextAppearance="@style/ToolbarTextAppearance" app:titleTextColor="@color/white" /> diff --git a/app/src/main/res/layout-land/audio_language_fragment.xml b/app/src/main/res/layout-land/audio_language_fragment.xml index bbbed18e304..451e75d7824 100644 --- a/app/src/main/res/layout-land/audio_language_fragment.xml +++ b/app/src/main/res/layout-land/audio_language_fragment.xml @@ -31,7 +31,7 @@ android:minHeight="?attr/actionBarSize" app:navigationContentDescription="@string/navigate_up" app:navigationIcon="?attr/homeAsUpIndicator" - app:title="@string/title_default_audio" + app:title="@string/audio_language_activity_title" app:titleTextAppearance="@style/ToolbarTextAppearance" app:titleTextColor="@color/white" /> diff --git a/app/src/main/res/layout-land/language_items.xml b/app/src/main/res/layout-land/language_items.xml index 6bdb022d7d6..6e3cc0fcd20 100644 --- a/app/src/main/res/layout-land/language_items.xml +++ b/app/src/main/res/layout-land/language_items.xml @@ -15,6 +15,7 @@ android:gravity="center_vertical" android:minHeight="48dp" android:onClick="@{() -> viewModel.languageRadioButtonListener.onLanguageSelected(viewModel.language)}" + android:importantForAccessibility="yes" android:orientation="horizontal"> diff --git a/app/src/main/res/layout/app_language_fragment.xml b/app/src/main/res/layout/app_language_fragment.xml index a02285784dd..5e60e30fa1a 100644 --- a/app/src/main/res/layout/app_language_fragment.xml +++ b/app/src/main/res/layout/app_language_fragment.xml @@ -31,7 +31,7 @@ android:minHeight="?attr/actionBarSize" app:navigationContentDescription="@string/navigate_up" app:navigationIcon="?attr/homeAsUpIndicator" - app:title="@string/title_app_language" + app:title="@string/app_language_activity_title" app:titleTextAppearance="@style/ToolbarTextAppearance" app:titleTextColor="@color/white" /> diff --git a/app/src/main/res/layout/audio_language_fragment.xml b/app/src/main/res/layout/audio_language_fragment.xml index 174f6efd057..ec805136b81 100644 --- a/app/src/main/res/layout/audio_language_fragment.xml +++ b/app/src/main/res/layout/audio_language_fragment.xml @@ -31,7 +31,7 @@ android:minHeight="?attr/actionBarSize" app:navigationContentDescription="@string/navigate_up" app:navigationIcon="?attr/homeAsUpIndicator" - app:title="@string/title_default_audio" + app:title="@string/audio_language_activity_title" app:titleTextAppearance="@style/ToolbarTextAppearance" app:titleTextColor="@color/white" /> diff --git a/app/src/main/res/layout/language_items.xml b/app/src/main/res/layout/language_items.xml index 6bdb022d7d6..6e3cc0fcd20 100755 --- a/app/src/main/res/layout/language_items.xml +++ b/app/src/main/res/layout/language_items.xml @@ -15,6 +15,7 @@ android:gravity="center_vertical" android:minHeight="48dp" android:onClick="@{() -> viewModel.languageRadioButtonListener.onLanguageSelected(viewModel.language)}" + android:importantForAccessibility="yes" android:orientation="horizontal"> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 97023f71176..83cab7ad60b 100755 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -337,9 +337,9 @@ App Version %s The last update was installed on %s. Use the above version number to send feedback about bugs. + App Language + Default Audio Language Reading Text Size - App Language - Default Audio Language Story text will look like this. A Default Audio diff --git a/app/src/sharedTest/java/org/oppia/android/app/options/AppLanguageActivityTest.kt b/app/src/sharedTest/java/org/oppia/android/app/options/AppLanguageActivityTest.kt new file mode 100644 index 00000000000..f8b707dbd12 --- /dev/null +++ b/app/src/sharedTest/java/org/oppia/android/app/options/AppLanguageActivityTest.kt @@ -0,0 +1,154 @@ +package org.oppia.android.app.options + +import android.app.Application +import android.content.Context +import android.content.Intent +import androidx.appcompat.app.AppCompatActivity +import androidx.test.core.app.ApplicationProvider +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.rule.ActivityTestRule +import com.google.common.truth.Truth.assertThat +import dagger.Component +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.oppia.android.R +import org.oppia.android.app.activity.ActivityComponent +import org.oppia.android.app.application.ActivityComponentFactory +import org.oppia.android.app.application.ApplicationComponent +import org.oppia.android.app.application.ApplicationInjector +import org.oppia.android.app.application.ApplicationInjectorProvider +import org.oppia.android.app.application.ApplicationModule +import org.oppia.android.app.application.ApplicationStartupListenerModule +import org.oppia.android.app.player.state.hintsandsolution.HintsAndSolutionConfigModule +import org.oppia.android.app.shim.ViewBindingShimModule +import org.oppia.android.domain.classify.InteractionsModule +import org.oppia.android.domain.classify.rules.continueinteraction.ContinueModule +import org.oppia.android.domain.classify.rules.dragAndDropSortInput.DragDropSortInputModule +import org.oppia.android.domain.classify.rules.fractioninput.FractionInputModule +import org.oppia.android.domain.classify.rules.imageClickInput.ImageClickInputModule +import org.oppia.android.domain.classify.rules.itemselectioninput.ItemSelectionInputModule +import org.oppia.android.domain.classify.rules.multiplechoiceinput.MultipleChoiceInputModule +import org.oppia.android.domain.classify.rules.numberwithunits.NumberWithUnitsRuleModule +import org.oppia.android.domain.classify.rules.numericinput.NumericInputRuleModule +import org.oppia.android.domain.classify.rules.ratioinput.RatioInputModule +import org.oppia.android.domain.classify.rules.textinput.TextInputRuleModule +import org.oppia.android.domain.onboarding.ExpirationMetaDataRetrieverModule +import org.oppia.android.domain.oppialogger.LogStorageModule +import org.oppia.android.domain.oppialogger.loguploader.LogUploadWorkerModule +import org.oppia.android.domain.oppialogger.loguploader.WorkManagerConfigurationModule +import org.oppia.android.domain.question.QuestionModule +import org.oppia.android.domain.topic.PrimeTopicAssetsControllerModule +import org.oppia.android.testing.RobolectricModule +import org.oppia.android.testing.TestDispatcherModule +import org.oppia.android.testing.TestLogReportingModule +import org.oppia.android.testing.time.FakeOppiaClockModule +import org.oppia.android.util.accessibility.AccessibilityTestModule +import org.oppia.android.util.caching.testing.CachingTestModule +import org.oppia.android.util.gcsresource.GcsResourceModule +import org.oppia.android.util.logging.LoggerModule +import org.oppia.android.util.logging.firebase.FirebaseLogUploaderModule +import org.oppia.android.util.parser.GlideImageLoaderModule +import org.oppia.android.util.parser.HtmlParserEntityTypeModule +import org.oppia.android.util.parser.ImageParsingModule +import org.robolectric.annotation.Config +import org.robolectric.annotation.LooperMode +import javax.inject.Inject +import javax.inject.Singleton + +/** Tests for [AppLanguageActivity]. */ +@RunWith(AndroidJUnit4::class) +@LooperMode(LooperMode.Mode.PAUSED) +@Config( + application = AppLanguageActivityTest.TestApplication::class, + qualifiers = "port-xxhdpi" +) +class AppLanguageActivityTest { + + @get:Rule + val activityTestRule: ActivityTestRule = ActivityTestRule( + AppLanguageActivity::class.java, /* initialTouchMode= */ true, /* launchActivity= */ false + ) + + @Inject + lateinit var context: Context + + private val summaryValue = "English" + + @Before + fun setUp() { + setUpTestApplicationComponent() + } + + private fun setUpTestApplicationComponent() { + ApplicationProvider.getApplicationContext().inject(this) + } + + @Test + fun testAppLanguageActivity_hasCorrectActivityLabel() { + activityTestRule.launchActivity( + createAppLanguageActivityIntent( + summaryValue + ) + ) + val title = activityTestRule.activity.title + // Verify that the activity label is correct as a proxy to verify TalkBack will announce the + // correct string when it's read out. + assertThat(title).isEqualTo(context.getString(R.string.app_language_activity_title)) + } + + private fun createAppLanguageActivityIntent(summaryValue: String): Intent { + return AppLanguageActivity.createAppLanguageActivityIntent( + ApplicationProvider.getApplicationContext(), + APP_LANGUAGE, + summaryValue + ) + } + + // TODO(#59): Figure out a way to reuse modules instead of needing to re-declare them. + // TODO(#1675): Add NetworkModule once data module is migrated off of Moshi. + @Singleton + @Component( + modules = [ + RobolectricModule::class, + TestDispatcherModule::class, ApplicationModule::class, + LoggerModule::class, ContinueModule::class, FractionInputModule::class, + ItemSelectionInputModule::class, MultipleChoiceInputModule::class, + NumberWithUnitsRuleModule::class, NumericInputRuleModule::class, TextInputRuleModule::class, + DragDropSortInputModule::class, ImageClickInputModule::class, InteractionsModule::class, + GcsResourceModule::class, GlideImageLoaderModule::class, ImageParsingModule::class, + HtmlParserEntityTypeModule::class, QuestionModule::class, TestLogReportingModule::class, + AccessibilityTestModule::class, LogStorageModule::class, CachingTestModule::class, + PrimeTopicAssetsControllerModule::class, ExpirationMetaDataRetrieverModule::class, + ViewBindingShimModule::class, RatioInputModule::class, + ApplicationStartupListenerModule::class, LogUploadWorkerModule::class, + WorkManagerConfigurationModule::class, HintsAndSolutionConfigModule::class, + FirebaseLogUploaderModule::class, FakeOppiaClockModule::class + ] + ) + interface TestApplicationComponent : ApplicationComponent { + @Component.Builder + interface Builder : ApplicationComponent.Builder + + fun inject(appLanguageActivityTest: AppLanguageActivityTest) + } + + class TestApplication : Application(), ActivityComponentFactory, ApplicationInjectorProvider { + private val component: TestApplicationComponent by lazy { + DaggerAppLanguageActivityTest_TestApplicationComponent.builder() + .setApplication(this) + .build() as TestApplicationComponent + } + + fun inject(appLanguageActivityTest: AppLanguageActivityTest) { + component.inject(appLanguageActivityTest) + } + + override fun createActivityComponent(activity: AppCompatActivity): ActivityComponent { + return component.getActivityComponentBuilderProvider().get().setActivity(activity).build() + } + + override fun getApplicationInjector(): ApplicationInjector = component + } +} diff --git a/app/src/sharedTest/java/org/oppia/android/app/options/AudioLanguageActivityTest.kt b/app/src/sharedTest/java/org/oppia/android/app/options/AudioLanguageActivityTest.kt new file mode 100644 index 00000000000..9fb409dd904 --- /dev/null +++ b/app/src/sharedTest/java/org/oppia/android/app/options/AudioLanguageActivityTest.kt @@ -0,0 +1,153 @@ +package org.oppia.android.app.options + +import android.app.Application +import android.content.Context +import android.content.Intent +import androidx.appcompat.app.AppCompatActivity +import androidx.test.core.app.ApplicationProvider +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.rule.ActivityTestRule +import com.google.common.truth.Truth.assertThat +import dagger.Component +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.oppia.android.R +import org.oppia.android.app.activity.ActivityComponent +import org.oppia.android.app.application.ActivityComponentFactory +import org.oppia.android.app.application.ApplicationComponent +import org.oppia.android.app.application.ApplicationInjector +import org.oppia.android.app.application.ApplicationInjectorProvider +import org.oppia.android.app.application.ApplicationModule +import org.oppia.android.app.application.ApplicationStartupListenerModule +import org.oppia.android.app.player.state.hintsandsolution.HintsAndSolutionConfigModule +import org.oppia.android.app.shim.ViewBindingShimModule +import org.oppia.android.domain.classify.InteractionsModule +import org.oppia.android.domain.classify.rules.continueinteraction.ContinueModule +import org.oppia.android.domain.classify.rules.dragAndDropSortInput.DragDropSortInputModule +import org.oppia.android.domain.classify.rules.fractioninput.FractionInputModule +import org.oppia.android.domain.classify.rules.imageClickInput.ImageClickInputModule +import org.oppia.android.domain.classify.rules.itemselectioninput.ItemSelectionInputModule +import org.oppia.android.domain.classify.rules.multiplechoiceinput.MultipleChoiceInputModule +import org.oppia.android.domain.classify.rules.numberwithunits.NumberWithUnitsRuleModule +import org.oppia.android.domain.classify.rules.numericinput.NumericInputRuleModule +import org.oppia.android.domain.classify.rules.ratioinput.RatioInputModule +import org.oppia.android.domain.classify.rules.textinput.TextInputRuleModule +import org.oppia.android.domain.onboarding.ExpirationMetaDataRetrieverModule +import org.oppia.android.domain.oppialogger.LogStorageModule +import org.oppia.android.domain.oppialogger.loguploader.LogUploadWorkerModule +import org.oppia.android.domain.oppialogger.loguploader.WorkManagerConfigurationModule +import org.oppia.android.domain.question.QuestionModule +import org.oppia.android.domain.topic.PrimeTopicAssetsControllerModule +import org.oppia.android.testing.RobolectricModule +import org.oppia.android.testing.TestDispatcherModule +import org.oppia.android.testing.TestLogReportingModule +import org.oppia.android.testing.time.FakeOppiaClockModule +import org.oppia.android.util.accessibility.AccessibilityTestModule +import org.oppia.android.util.caching.testing.CachingTestModule +import org.oppia.android.util.gcsresource.GcsResourceModule +import org.oppia.android.util.logging.LoggerModule +import org.oppia.android.util.logging.firebase.FirebaseLogUploaderModule +import org.oppia.android.util.parser.GlideImageLoaderModule +import org.oppia.android.util.parser.HtmlParserEntityTypeModule +import org.oppia.android.util.parser.ImageParsingModule +import org.robolectric.annotation.Config +import org.robolectric.annotation.LooperMode +import javax.inject.Inject +import javax.inject.Singleton + +/** Tests for [AudioLanguageActivity]. */ +@RunWith(AndroidJUnit4::class) +@LooperMode(LooperMode.Mode.PAUSED) +@Config( + application = AudioLanguageActivityTest.TestApplication::class, + qualifiers = "port-xxhdpi" +) +class AudioLanguageActivityTest { + @get:Rule + val activityTestRule: ActivityTestRule = ActivityTestRule( + AudioLanguageActivity::class.java, /* initialTouchMode= */ true, /* launchActivity= */ false + ) + + @Inject + lateinit var context: Context + + private val summaryValue = "English" + + @Before + fun setUp() { + setUpTestApplicationComponent() + } + + private fun setUpTestApplicationComponent() { + ApplicationProvider.getApplicationContext().inject(this) + } + + @Test + fun testAudioLanguageActivity_hasCorrectActivityLabel() { + activityTestRule.launchActivity( + createDefaultAudioActivityIntent( + summaryValue + ) + ) + val title = activityTestRule.activity.title + // Verify that the activity label is correct as a proxy to verify TalkBack will announce the + // correct string when it's read out. + assertThat(title).isEqualTo(context.getString(R.string.audio_language_activity_title)) + } + + private fun createDefaultAudioActivityIntent(summaryValue: String): Intent { + return AudioLanguageActivity.createAudioLanguageActivityIntent( + ApplicationProvider.getApplicationContext(), + AUDIO_LANGUAGE, + summaryValue + ) + } + + // TODO(#59): Figure out a way to reuse modules instead of needing to re-declare them. + // TODO(#1675): Add NetworkModule once data module is migrated off of Moshi. + @Singleton + @Component( + modules = [ + RobolectricModule::class, + TestDispatcherModule::class, ApplicationModule::class, + LoggerModule::class, ContinueModule::class, FractionInputModule::class, + ItemSelectionInputModule::class, MultipleChoiceInputModule::class, + NumberWithUnitsRuleModule::class, NumericInputRuleModule::class, TextInputRuleModule::class, + DragDropSortInputModule::class, ImageClickInputModule::class, InteractionsModule::class, + GcsResourceModule::class, GlideImageLoaderModule::class, ImageParsingModule::class, + HtmlParserEntityTypeModule::class, QuestionModule::class, TestLogReportingModule::class, + AccessibilityTestModule::class, LogStorageModule::class, CachingTestModule::class, + PrimeTopicAssetsControllerModule::class, ExpirationMetaDataRetrieverModule::class, + ViewBindingShimModule::class, RatioInputModule::class, + ApplicationStartupListenerModule::class, LogUploadWorkerModule::class, + WorkManagerConfigurationModule::class, HintsAndSolutionConfigModule::class, + FirebaseLogUploaderModule::class, FakeOppiaClockModule::class + ] + ) + interface TestApplicationComponent : ApplicationComponent { + @Component.Builder + interface Builder : ApplicationComponent.Builder + + fun inject(audioLanguageActivityTest: AudioLanguageActivityTest) + } + + class TestApplication : Application(), ActivityComponentFactory, ApplicationInjectorProvider { + private val component: TestApplicationComponent by lazy { + DaggerAudioLanguageActivityTest_TestApplicationComponent.builder() + .setApplication(this) + .build() as TestApplicationComponent + } + + fun inject(audioLanguageActivityTest: AudioLanguageActivityTest) { + component.inject(audioLanguageActivityTest) + } + + override fun createActivityComponent(activity: AppCompatActivity): ActivityComponent { + return component.getActivityComponentBuilderProvider().get().setActivity(activity).build() + } + + override fun getApplicationInjector(): ApplicationInjector = component + } +}