From 57d13ad0180956d755980f93c4e6f5ba36ba7ab4 Mon Sep 17 00:00:00 2001 From: Angela Wang Date: Thu, 21 Apr 2022 15:29:33 +0000 Subject: [PATCH] Add a button to the accessibility button tutorial dialog that links directly to the settings page. When the accessibility button appears, some users don't know how to control it. Add a button to the tutorial dialog that links directly to the settings page to help users get more information. Bug: 183977141 Test: make RunSettingsRoboTests ROBOTEST_FILTER=AccessibilityGestureNavigationTutorialTest Change-Id: I08d7e5b0771b6bf99f7753ccbcf2e7400227ddc5 --- res/values/strings.xml | 2 + ...ccessibilityGestureNavigationTutorial.java | 77 +++++++++++++++---- ...sibilityGestureNavigationTutorialTest.java | 34 +++++++- 3 files changed, 96 insertions(+), 17 deletions(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index 88f57001419..73795e2c9de 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -5395,6 +5395,8 @@ To use an accessibility feature, swipe up from the bottom of the screen with 3 fingers.\n\nTo switch between features, swipe up with 3 fingers and hold. Got it + + Accessibility button settings %1$s shortcut diff --git a/src/com/android/settings/accessibility/AccessibilityGestureNavigationTutorial.java b/src/com/android/settings/accessibility/AccessibilityGestureNavigationTutorial.java index 773c9878e9d..95469d4bc2f 100644 --- a/src/com/android/settings/accessibility/AccessibilityGestureNavigationTutorial.java +++ b/src/com/android/settings/accessibility/AccessibilityGestureNavigationTutorial.java @@ -21,6 +21,7 @@ import static android.view.View.VISIBLE; import static com.android.settings.accessibility.AccessibilityUtil.UserShortcutType; +import android.app.settings.SettingsEnums; import android.content.Context; import android.content.DialogInterface; import android.content.res.TypedArray; @@ -57,6 +58,7 @@ import androidx.viewpager.widget.PagerAdapter; import androidx.viewpager.widget.ViewPager; import com.android.settings.R; +import com.android.settings.core.SubSettingLauncher; import com.airbnb.lottie.LottieAnimationView; import com.airbnb.lottie.LottieDrawable; @@ -130,12 +132,29 @@ public final class AccessibilityGestureNavigationTutorial { } static AlertDialog createAccessibilityTutorialDialog(Context context, int shortcutTypes, - @Nullable DialogInterface.OnClickListener negativeButtonListener) { - return new AlertDialog.Builder(context) - .setView(createShortcutNavigationContentView(context, shortcutTypes)) - .setNegativeButton(R.string.accessibility_tutorial_dialog_button, - negativeButtonListener) + @Nullable DialogInterface.OnClickListener actionButtonListener) { + + final int category = SettingsEnums.SWITCH_SHORTCUT_DIALOG_ACCESSIBILITY_BUTTON_SETTINGS; + final DialogInterface.OnClickListener linkButtonListener = + (dialog, which) -> new SubSettingLauncher(context) + .setDestination(AccessibilityButtonFragment.class.getName()) + .setSourceMetricsCategory(category) + .launch(); + + final AlertDialog alertDialog = new AlertDialog.Builder(context) + .setNegativeButton(R.string.accessibility_tutorial_dialog_link_button, + linkButtonListener) + .setPositiveButton(R.string.accessibility_tutorial_dialog_button, + actionButtonListener) .create(); + + final TutorialPageChangeListener.OnPageSelectedCallback callback = + type -> alertDialog.getButton(DialogInterface.BUTTON_NEGATIVE).setVisibility( + type == UserShortcutType.SOFTWARE ? VISIBLE : GONE); + + alertDialog.setView(createShortcutNavigationContentView(context, shortcutTypes, callback)); + + return alertDialog; } /** @@ -311,7 +330,9 @@ public final class AccessibilityGestureNavigationTutorial { return inflater.inflate(R.layout.accessibility_lottie_animation_view, /* root= */ null); } - private static View createShortcutNavigationContentView(Context context, int shortcutTypes) { + private static View createShortcutNavigationContentView(Context context, int shortcutTypes, + TutorialPageChangeListener.OnPageSelectedCallback onPageSelectedCallback) { + final LayoutInflater inflater = context.getSystemService(LayoutInflater.class); final View contentView = inflater.inflate( R.layout.accessibility_shortcut_tutorial_dialog, /* root= */ null); @@ -342,9 +363,10 @@ public final class AccessibilityGestureNavigationTutorial { viewPager.setImportantForAccessibility(tutorialPages.size() > 1 ? View.IMPORTANT_FOR_ACCESSIBILITY_YES : View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS); - viewPager.addOnPageChangeListener( - new TutorialPageChangeListener(context, viewPager, title, instruction, - tutorialPages)); + + TutorialPageChangeListener listener = new TutorialPageChangeListener(context, viewPager, + title, instruction, tutorialPages); + listener.setOnPageSelectedCallback(onPageSelectedCallback); return contentView; } @@ -365,6 +387,7 @@ public final class AccessibilityGestureNavigationTutorial { } private static TutorialPage createSoftwareTutorialPage(@NonNull Context context) { + final int type = UserShortcutType.SOFTWARE; final CharSequence title = getSoftwareTitle(context); final View image = createSoftwareImage(context); final CharSequence instruction = getSoftwareInstruction(context); @@ -372,10 +395,11 @@ public final class AccessibilityGestureNavigationTutorial { createImageView(context, R.drawable.ic_accessibility_page_indicator); indicatorIcon.setEnabled(false); - return new TutorialPage(title, image, indicatorIcon, instruction); + return new TutorialPage(type, title, image, indicatorIcon, instruction); } private static TutorialPage createHardwareTutorialPage(@NonNull Context context) { + final int type = UserShortcutType.HARDWARE; final CharSequence title = context.getText(R.string.accessibility_tutorial_dialog_title_volume); final View image = @@ -386,10 +410,11 @@ public final class AccessibilityGestureNavigationTutorial { context.getText(R.string.accessibility_tutorial_dialog_message_volume); indicatorIcon.setEnabled(false); - return new TutorialPage(title, image, indicatorIcon, instruction); + return new TutorialPage(type, title, image, indicatorIcon, instruction); } private static TutorialPage createTripleTapTutorialPage(@NonNull Context context) { + final int type = UserShortcutType.TRIPLETAP; final CharSequence title = context.getText(R.string.accessibility_tutorial_dialog_title_triple); final View image = @@ -401,7 +426,7 @@ public final class AccessibilityGestureNavigationTutorial { createImageView(context, R.drawable.ic_accessibility_page_indicator); indicatorIcon.setEnabled(false); - return new TutorialPage(title, image, indicatorIcon, instruction); + return new TutorialPage(type, title, image, indicatorIcon, instruction); } @VisibleForTesting @@ -485,13 +510,15 @@ public final class AccessibilityGestureNavigationTutorial { } private static class TutorialPage { + private final int mType; private final CharSequence mTitle; private final View mIllustrationView; private final ImageView mIndicatorIcon; private final CharSequence mInstruction; - TutorialPage(CharSequence title, View illustrationView, ImageView indicatorIcon, + TutorialPage(int type, CharSequence title, View illustrationView, ImageView indicatorIcon, CharSequence instruction) { + this.mType = type; this.mTitle = title; this.mIllustrationView = illustrationView; this.mIndicatorIcon = indicatorIcon; @@ -500,6 +527,10 @@ public final class AccessibilityGestureNavigationTutorial { setupIllustrationChildViewsGravity(); } + public int getType() { + return mType; + } + public CharSequence getTitle() { return mTitle; } @@ -541,6 +572,7 @@ public final class AccessibilityGestureNavigationTutorial { private final TextSwitcher mInstruction; private final List mTutorialPages; private final ViewPager mViewPager; + private OnPageSelectedCallback mOnPageSelectedCallback; TutorialPageChangeListener(Context context, ViewPager viewPager, ViewGroup title, ViewGroup instruction, List tutorialPages) { @@ -549,6 +581,14 @@ public final class AccessibilityGestureNavigationTutorial { this.mTitle = (TextSwitcher) title; this.mInstruction = (TextSwitcher) instruction; this.mTutorialPages = tutorialPages; + this.mOnPageSelectedCallback = null; + + this.mViewPager.addOnPageChangeListener(this); + } + + public void setOnPageSelectedCallback( + OnPageSelectedCallback callback) { + this.mOnPageSelectedCallback = callback; } @Override @@ -589,11 +629,22 @@ public final class AccessibilityGestureNavigationTutorial { mViewPager.setContentDescription( mContext.getString(R.string.accessibility_tutorial_pager, currentPageNumber, mTutorialPages.size())); + + if (mOnPageSelectedCallback != null) { + mOnPageSelectedCallback.onPageSelected(mTutorialPages.get(position).getType()); + } } @Override public void onPageScrollStateChanged(int state) { // Do nothing. } + + /** The interface that provides a callback method after tutorial page is selected. */ + private interface OnPageSelectedCallback { + + /** The callback method after tutorial page is selected. */ + void onPageSelected(int type); + } } } diff --git a/tests/robotests/src/com/android/settings/accessibility/AccessibilityGestureNavigationTutorialTest.java b/tests/robotests/src/com/android/settings/accessibility/AccessibilityGestureNavigationTutorialTest.java index 6efdcf7a7e2..ceb630c6d3b 100644 --- a/tests/robotests/src/com/android/settings/accessibility/AccessibilityGestureNavigationTutorialTest.java +++ b/tests/robotests/src/com/android/settings/accessibility/AccessibilityGestureNavigationTutorialTest.java @@ -23,14 +23,21 @@ import static com.android.settings.accessibility.AccessibilityUtil.UserShortcutT import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.verify; +import static org.robolectric.Shadows.shadowOf; +import android.app.Activity; +import android.app.settings.SettingsEnums; import android.content.Context; import android.content.DialogInterface; +import android.content.Intent; import androidx.appcompat.app.AlertDialog; import androidx.test.core.app.ApplicationProvider; import com.android.settings.R; +import com.android.settings.SettingsActivity; +import com.android.settings.SubSettings; +import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import org.junit.Before; import org.junit.Rule; @@ -39,6 +46,7 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; +import org.robolectric.Robolectric; import org.robolectric.RobolectricTestRunner; /** Tests for {@link AccessibilityGestureNavigationTutorial}. */ @@ -103,26 +111,44 @@ public final class AccessibilityGestureNavigationTutorialTest { } @Test - public void performClickOnNegativeButton_turnOnSoftwareShortcut_dismiss() { + public void performClickOnPositiveButton_turnOnSoftwareShortcut_dismiss() { mShortcutTypes |= UserShortcutType.SOFTWARE; final AlertDialog alertDialog = createAccessibilityTutorialDialog(mContext, mShortcutTypes); alertDialog.show(); - alertDialog.getButton(DialogInterface.BUTTON_NEGATIVE).performClick(); + alertDialog.getButton(DialogInterface.BUTTON_POSITIVE).performClick(); assertThat(alertDialog.isShowing()).isFalse(); } @Test - public void performClickOnNegativeButton_turnOnSoftwareShortcut_callOnClickListener() { + public void performClickOnPositiveButton_turnOnSoftwareShortcut_callOnClickListener() { mShortcutTypes |= UserShortcutType.SOFTWARE; final AlertDialog alertDialog = createAccessibilityTutorialDialog(mContext, mShortcutTypes, mMockOnClickListener); alertDialog.show(); + alertDialog.getButton(DialogInterface.BUTTON_POSITIVE).performClick(); + + verify(mMockOnClickListener).onClick(alertDialog, DialogInterface.BUTTON_POSITIVE); + } + + @Test + public void performClickOnNegativeButton_turnOnSoftwareShortcut_directToSettingsPage() { + mShortcutTypes |= UserShortcutType.SOFTWARE; + Activity activity = Robolectric.buildActivity(Activity.class).create().get(); + final AlertDialog alertDialog = + createAccessibilityTutorialDialog(activity, mShortcutTypes, mMockOnClickListener); + alertDialog.show(); + alertDialog.getButton(DialogInterface.BUTTON_NEGATIVE).performClick(); - verify(mMockOnClickListener).onClick(alertDialog, DialogInterface.BUTTON_NEGATIVE); + final Intent intent = shadowOf(activity).peekNextStartedActivity(); + assertThat(intent.getComponent().getClassName()).isEqualTo(SubSettings.class.getName()); + assertThat(intent.getStringExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT)) + .isEqualTo(AccessibilityButtonFragment.class.getName()); + assertThat(intent.getIntExtra(MetricsFeatureProvider.EXTRA_SOURCE_METRICS_CATEGORY, -1)) + .isEqualTo(SettingsEnums.SWITCH_SHORTCUT_DIALOG_ACCESSIBILITY_BUTTON_SETTINGS); } }