Update home, back and overview gesture tutorial introductions to be clearer for blind users

Added A11Y strings for the home, back and overview gesture tutorial step introductions. These strings give clearer instructions that work with talkback.

Fixes: 202492454
Test: manual
Change-Id: I1eefd6ecf3e3c576a7c1cf6dbf7b824e5be13860
diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml
index f80deeb..81b0dd2 100644
--- a/quickstep/res/values/strings.xml
+++ b/quickstep/res/values/strings.xml
@@ -109,6 +109,8 @@
     <string name="back_gesture_intro_title">Swipe to go back</string>
     <!-- Introduction subtitle for the Back gesture tutorial. [CHAR LIMIT=200] -->
     <string name="back_gesture_intro_subtitle">To go back to the last screen, swipe from the left or right edge to the middle of the screen.</string>
+    <!-- Introduction subtitle for the Back gesture tutorial that will be spoken by screen readers. [CHAR LIMIT=200] -->
+    <string name="back_gesture_spoken_intro_subtitle">To go back to the last screen, swipe with 2 fingers from the left or right edge to the middle of the screen.</string>
 
     <string name="home_gesture_feedback_swipe_too_far_from_edge">Make sure you swipe up from the bottom edge of the screen.</string>
     <!-- Feedback shown during interactive parts of Home gesture tutorial when the Overview gesture is detected. [CHAR LIMIT=100] -->
@@ -123,6 +125,8 @@
     <string name="home_gesture_intro_title">Swipe to go home</string>
     <!-- Introduction subtitle for the Home gesture tutorial. [CHAR LIMIT=100] -->
     <string name="home_gesture_intro_subtitle">Swipe up from the bottom of your screen. This gesture always takes you to the Home screen.</string>
+    <!-- Introduction subtitle for the Home gesture tutorial that will be spoken by screen readers. [CHAR LIMIT=100] -->
+    <string name="home_gesture_spoken_intro_subtitle">Swipe up with 2 fingers from the bottom of the screen. This gesture always takes you to the Home screen.</string>
 
     <!-- Feedback shown during interactive parts of Overview gesture tutorial when the gesture is started too far from the edge. [CHAR LIMIT=100] -->
     <string name="overview_gesture_feedback_swipe_too_far_from_edge">Make sure you swipe up from the bottom edge of the screen.</string>
@@ -138,6 +142,8 @@
     <string name="overview_gesture_intro_title">Swipe to switch apps</string>
     <!-- Introduction subtitle for the Overview gesture tutorial. [CHAR LIMIT=100] -->
     <string name="overview_gesture_intro_subtitle">To switch between apps, swipe up from the bottom of your screen, hold, then release.</string>
+    <!-- Introduction subtitle for the Overview gesture tutorial that will be spoken by screen readers. [CHAR LIMIT=100] -->
+    <string name="overview_gesture_spoken_intro_subtitle">To switch between apps, swipe up with 2 fingers from the bottom of your screen, hold, then release.</string>
 
     <!-- Title shown during interactive part of Assistant gesture tutorial. [CHAR LIMIT=30] -->
     <string name="assistant_gesture_tutorial_playground_title" translatable="false">Tutorial: Assistant</string>
diff --git a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java
index 9ba5577..35d9f22 100644
--- a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java
@@ -33,17 +33,22 @@
     }
 
     @Override
-    public Integer getIntroductionTitle() {
+    public int getIntroductionTitle() {
         return R.string.back_gesture_intro_title;
     }
 
     @Override
-    public Integer getIntroductionSubtitle() {
+    public int getIntroductionSubtitle() {
         return R.string.back_gesture_intro_subtitle;
     }
 
     @Override
-    public Integer getSuccessFeedbackSubtitle() {
+    public int getSpokenIntroductionSubtitle() {
+        return R.string.back_gesture_spoken_intro_subtitle;
+    }
+
+    @Override
+    public int getSuccessFeedbackSubtitle() {
         return mTutorialFragment.isAtFinalStep()
                 ? R.string.back_gesture_feedback_complete_without_follow_up
                 : R.string.back_gesture_feedback_complete_with_overview_follow_up;
diff --git a/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java
index 6254313..f519d50 100644
--- a/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java
@@ -32,17 +32,22 @@
     }
 
     @Override
-    public Integer getIntroductionTitle() {
+    public int getIntroductionTitle() {
         return R.string.home_gesture_intro_title;
     }
 
     @Override
-    public Integer getIntroductionSubtitle() {
+    public int getIntroductionSubtitle() {
         return R.string.home_gesture_intro_subtitle;
     }
 
     @Override
-    public Integer getSuccessFeedbackSubtitle() {
+    public int getSpokenIntroductionSubtitle() {
+        return R.string.home_gesture_spoken_intro_subtitle;
+    }
+
+    @Override
+    public int getSuccessFeedbackSubtitle() {
         return mTutorialFragment.isAtFinalStep()
                 ? R.string.home_gesture_feedback_complete_without_follow_up
                 : R.string.home_gesture_feedback_complete_with_follow_up;
diff --git a/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java
index 09640c6..6b016ce 100644
--- a/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java
@@ -42,17 +42,22 @@
     }
 
     @Override
-    public Integer getIntroductionTitle() {
+    public int getIntroductionTitle() {
         return R.string.overview_gesture_intro_title;
     }
 
     @Override
-    public Integer getIntroductionSubtitle() {
+    public int getIntroductionSubtitle() {
         return R.string.overview_gesture_intro_subtitle;
     }
 
     @Override
-    public Integer getSuccessFeedbackSubtitle() {
+    public int getSpokenIntroductionSubtitle() {
+        return R.string.overview_gesture_spoken_intro_subtitle;
+    }
+
+    @Override
+    public int getSuccessFeedbackSubtitle() {
         return mTutorialFragment.getNumSteps() > 1 && mTutorialFragment.isAtFinalStep()
                 ? R.string.overview_gesture_feedback_complete_with_follow_up
                 : R.string.overview_gesture_feedback_complete_without_follow_up;
diff --git a/quickstep/src/com/android/quickstep/interaction/TutorialController.java b/quickstep/src/com/android/quickstep/interaction/TutorialController.java
index 6a8894e..fa7d848 100644
--- a/quickstep/src/com/android/quickstep/interaction/TutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/TutorialController.java
@@ -62,7 +62,7 @@
 abstract class TutorialController implements BackGestureAttemptCallback,
         NavBarGestureAttemptCallback {
 
-    private static final String TAG = "TutorialController";
+    private static final String LOG_TAG = "TutorialController";
 
     private static final float FINGER_DOT_VISIBLE_ALPHA = 0.7f;
     private static final float FINGER_DOT_SMALL_SCALE = 0.7f;
@@ -217,18 +217,23 @@
     }
 
     @StringRes
-    public Integer getIntroductionTitle() {
-        return null;
+    public int getIntroductionTitle() {
+        return NO_ID;
     }
 
     @StringRes
-    public Integer getIntroductionSubtitle() {
-        return null;
+    public int getIntroductionSubtitle() {
+        return NO_ID;
     }
 
     @StringRes
-    public Integer getSuccessFeedbackSubtitle() {
-        return null;
+    public int getSpokenIntroductionSubtitle() {
+        return NO_ID;
+    }
+
+    @StringRes
+    public int getSuccessFeedbackSubtitle() {
+        return NO_ID;
     }
 
     void showFeedback() {
@@ -247,7 +252,16 @@
      * Show feedback reflecting a successful gesture attempt.
      **/
     void showSuccessFeedback() {
-        showFeedback(getSuccessFeedbackSubtitle(), true);
+        int successSubtitleResId = getSuccessFeedbackSubtitle();
+        if (successSubtitleResId == NO_ID) {
+            // Allow crash since this should never be reached with a tutorial controller used in
+            // production.
+            Log.e(LOG_TAG,
+                    "Cannot show success feedback for tutorial step: " + mTutorialType
+                            + ", no success feedback subtitle",
+                    new IllegalStateException());
+        }
+        showFeedback(successSubtitleResId, true);
     }
 
     /**
@@ -269,6 +283,7 @@
                 isGestureSuccessful
                         ? R.string.gesture_tutorial_nice : R.string.gesture_tutorial_try_again,
                 subtitleResId,
+                NO_ID,
                 isGestureSuccessful,
                 false);
     }
@@ -276,6 +291,7 @@
     void showFeedback(
             int titleResId,
             int subtitleResId,
+            int spokenSubtitleResId,
             boolean isGestureSuccessful,
             boolean useGestureAnimationDelay) {
         mFeedbackTitleView.removeCallbacks(mTitleViewCallback);
@@ -287,7 +303,10 @@
         mFeedbackTitleView.setText(titleResId);
         TextView subtitle =
                 mFeedbackView.findViewById(R.id.gesture_tutorial_fragment_feedback_subtitle);
-        subtitle.setText(subtitleResId);
+        subtitle.setText(spokenSubtitleResId == NO_ID
+                ? mContext.getText(subtitleResId)
+                : Utilities.wrapForTts(
+                        mContext.getText(subtitleResId), mContext.getString(spokenSubtitleResId)));
         if (isGestureSuccessful) {
             if (mTutorialFragment.isAtFinalStep()) {
                 showActionButton();
@@ -580,7 +599,7 @@
                         packageManager.getApplicationInfo(
                                 PIXEL_TIPS_APP_PACKAGE_NAME, PackageManager.GET_META_DATA));
             } catch (PackageManager.NameNotFoundException e) {
-                Log.e(TAG,
+                Log.e(LOG_TAG,
                         "Could not find app label for package name: "
                                 + PIXEL_TIPS_APP_PACKAGE_NAME
                                 + ". Defaulting to 'Pixel Tips.'",
@@ -593,7 +612,7 @@
                 subtitleTextView.setText(
                         mContext.getString(R.string.skip_tutorial_dialog_subtitle, tipsAppName));
             } else {
-                Log.w(TAG, "No subtitle view in the skip tutorial dialog to update.");
+                Log.w(LOG_TAG, "No subtitle view in the skip tutorial dialog to update.");
             }
 
             Button cancelButton = (Button) contentView.findViewById(
@@ -602,7 +621,7 @@
                 cancelButton.setOnClickListener(
                         v -> tutorialDialog.dismiss());
             } else {
-                Log.w(TAG, "No cancel button in the skip tutorial dialog to update.");
+                Log.w(LOG_TAG, "No cancel button in the skip tutorial dialog to update.");
             }
 
             Button confirmButton = contentView.findViewById(
@@ -613,7 +632,7 @@
                     tutorialDialog.dismiss();
                 });
             } else {
-                Log.w(TAG, "No confirm button in the skip tutorial dialog to update.");
+                Log.w(LOG_TAG, "No confirm button in the skip tutorial dialog to update.");
             }
 
             tutorialDialog.getWindow().setBackgroundDrawable(
diff --git a/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java b/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java
index 33e800d..1599c8c 100644
--- a/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java
+++ b/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java
@@ -15,6 +15,8 @@
  */
 package com.android.quickstep.interaction;
 
+import static android.view.View.NO_ID;
+
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.app.Activity;
@@ -211,13 +213,31 @@
         if (isGestureComplete()) {
             mTutorialController.showSuccessFeedback();
         } else if (!mIntroductionShown) {
-            Integer introTileStringResId = mTutorialController.getIntroductionTitle();
-            Integer introSubtitleResId = mTutorialController.getIntroductionSubtitle();
-            if (introTileStringResId != null && introSubtitleResId != null) {
-                mTutorialController.showFeedback(
-                        introTileStringResId, introSubtitleResId, false, true);
-                mIntroductionShown = true;
+            int introTitleResId = mTutorialController.getIntroductionTitle();
+            int introSubtitleResId = mTutorialController.getIntroductionSubtitle();
+            if (introTitleResId == NO_ID) {
+                // Allow crash since this should never be reached with a tutorial controller used in
+                // production.
+                Log.e(LOG_TAG,
+                        "Cannot show introduction feedback for tutorial step: " + mTutorialType
+                                + ", no introduction feedback title",
+                        new IllegalStateException());
             }
+            if (introTitleResId == NO_ID) {
+                // Allow crash since this should never be reached with a tutorial controller used in
+                // production.
+                Log.e(LOG_TAG,
+                        "Cannot show introduction feedback for tutorial step: " + mTutorialType
+                                + ", no introduction feedback subtitle",
+                        new IllegalStateException());
+            }
+            mTutorialController.showFeedback(
+                    introTitleResId,
+                    introSubtitleResId,
+                    mTutorialController.getSpokenIntroductionSubtitle(),
+                    false,
+                    true);
+            mIntroductionShown = true;
         }
     }