Merge "Update home, back and overview gesture tutorial introductions to be clearer for blind users" into tm-dev
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;
         }
     }