From 7f70f5b6335382c0f6f811a34ff2583384683662 Mon Sep 17 00:00:00 2001 From: Candice Date: Tue, 25 Feb 2025 07:20:31 +0000 Subject: [PATCH] Add a content description for the illustration if it is an animation Since `isAnimatable` is decided in `onBindViewHolder`, we need to register an onBindListener and update the content description if the current illustration is an animation. For the static images, we would like to skip them in Talkback since they are decorative images. Bug: 395882764 Test: manually. attach screenshot to the bug Test: atest ToggleFeaturePreferenceFragmentTest flag: EXEMPT. bugfix Change-Id: I57bf96d0891ba553ef29d25ae9489f34b2a832e9 --- res/values/strings.xml | 2 + .../ToggleFeaturePreferenceFragment.java | 42 +++++++++++++----- .../ToggleFeaturePreferenceFragmentTest.java | 43 +++++++++++++++++++ 3 files changed, 77 insertions(+), 10 deletions(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index 003cd9bdc2a..24839ffb082 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -14293,4 +14293,6 @@ Data usage charges may apply. Forgot PIN Web content filters + + %1$s animation diff --git a/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java b/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java index 66c32df1798..d8c39856368 100644 --- a/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java +++ b/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java @@ -68,6 +68,7 @@ import com.android.settings.dashboard.DashboardFragment; import com.android.settings.flags.Flags; import com.android.settings.widget.SettingsMainSwitchBar; import com.android.settings.widget.SettingsMainSwitchPreference; +import com.android.settingslib.utils.ThreadUtils; import com.android.settingslib.widget.IllustrationPreference; import com.android.settingslib.widget.TopIntroPreference; @@ -311,6 +312,11 @@ public abstract class ToggleFeaturePreferenceFragment extends DashboardFragment return getString(R.string.accessibility_shortcut_title, mFeatureName); } + @VisibleForTesting + CharSequence getContentDescriptionForAnimatedIllustration() { + return getString(R.string.accessibility_illustration_content_description, mFeatureName); + } + protected void onPreferenceToggled(String preferenceKey, boolean enabled) { } @@ -427,22 +433,38 @@ public abstract class ToggleFeaturePreferenceFragment extends DashboardFragment return drawable; } - private void initAnimatedImagePreference() { - if (mImageUri == null) { + initAnimatedImagePreference(mImageUri, new IllustrationPreference(getPrefContext())); + } + + @VisibleForTesting + void initAnimatedImagePreference( + @Nullable Uri imageUri, + @NonNull IllustrationPreference preference) { + if (imageUri == null) { return; } final int displayHalfHeight = AccessibilityUtil.getDisplayBounds(getPrefContext()).height() / 2; - final IllustrationPreference illustrationPreference = - new IllustrationPreference(getPrefContext()); - illustrationPreference.setImageUri(mImageUri); - illustrationPreference.setSelectable(false); - illustrationPreference.setMaxHeight(displayHalfHeight); - illustrationPreference.setKey(KEY_ANIMATED_IMAGE); - - getPreferenceScreen().addPreference(illustrationPreference); + preference.setImageUri(imageUri); + preference.setSelectable(false); + preference.setMaxHeight(displayHalfHeight); + preference.setKey(KEY_ANIMATED_IMAGE); + preference.setOnBindListener(view -> { + // isAnimatable is decided in + // {@link IllustrationPreference#onBindViewHolder(PreferenceViewHolder)}. Therefore, we + // wait until the view is bond to set the content description for it. + // The content description is added for an animation illustration only. Since the static + // images are decorative. + ThreadUtils.getUiThreadHandler().post(() -> { + if (preference.isAnimatable()) { + preference.setContentDescription( + getContentDescriptionForAnimatedIllustration()); + } + }); + }); + getPreferenceScreen().addPreference(preference); } @VisibleForTesting diff --git a/tests/robotests/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragmentTest.java b/tests/robotests/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragmentTest.java index 571075cba31..f72b591353a 100644 --- a/tests/robotests/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragmentTest.java +++ b/tests/robotests/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragmentTest.java @@ -39,6 +39,7 @@ import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.icu.text.CaseMap; +import android.net.Uri; import android.os.Bundle; import android.platform.test.annotations.DisableFlags; import android.platform.test.annotations.EnableFlags; @@ -56,12 +57,14 @@ import androidx.fragment.app.FragmentActivity; import androidx.preference.Preference; import androidx.preference.PreferenceManager; import androidx.preference.PreferenceScreen; +import androidx.preference.PreferenceViewHolder; import androidx.test.core.app.ApplicationProvider; import com.android.settings.R; import com.android.settings.flags.Flags; import com.android.settings.testutils.shadow.ShadowAccessibilityManager; import com.android.settings.testutils.shadow.ShadowFragment; +import com.android.settingslib.widget.IllustrationPreference; import com.android.settingslib.widget.TopIntroPreference; import com.google.android.setupcompat.util.WizardManagerHelper; @@ -79,6 +82,7 @@ import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; import org.robolectric.shadow.api.Shadow; import org.robolectric.shadows.ShadowApplication; +import org.robolectric.shadows.ShadowLooper; import java.util.List; import java.util.Locale; @@ -315,6 +319,45 @@ public class ToggleFeaturePreferenceFragmentTest { assertThat(mFragment.getPreferenceScreen().getPreferenceCount()).isEqualTo(0); } + @Test + public void initAnimatedImagePreference_isAnimatable_setContentDescription() { + mFragment.mFeatureName = "Test Feature"; + final View view = + LayoutInflater.from(mContext).inflate( + com.android.settingslib.widget.preference.illustration + .R.layout.illustration_preference, + null); + IllustrationPreference preference = spy(new IllustrationPreference(mFragment.getContext())); + when(preference.isAnimatable()).thenReturn(true); + mFragment.initAnimatedImagePreference(mock(Uri.class), preference); + + preference.onBindViewHolder(PreferenceViewHolder.createInstanceForTests(view)); + ShadowLooper.runUiThreadTasksIncludingDelayedTasks(); + + String expectedContentDescription = mFragment.getString( + R.string.accessibility_illustration_content_description, mFragment.mFeatureName); + assertThat(preference.getContentDescription().toString()) + .isEqualTo(expectedContentDescription); + } + + @Test + public void initAnimatedImagePreference_isNotAnimatable_notSetContentDescription() { + mFragment.mFeatureName = "Test Feature"; + final View view = + LayoutInflater.from(mContext).inflate( + com.android.settingslib.widget.preference.illustration + .R.layout.illustration_preference, + null); + IllustrationPreference preference = spy(new IllustrationPreference(mFragment.getContext())); + when(preference.isAnimatable()).thenReturn(false); + mFragment.initAnimatedImagePreference(mock(Uri.class), preference); + + preference.onBindViewHolder(PreferenceViewHolder.createInstanceForTests(view)); + ShadowLooper.runUiThreadTasksIncludingDelayedTasks(); + + verify(preference, never()).setContentDescription(any()); + } + @Test @EnableFlags(Flags.FLAG_ACCESSIBILITY_SHOW_APP_INFO_BUTTON) public void createAppInfoPreference_withValidComponentName() {