Merge "Fix talkback not automatically announcing in Gesture Nav Tutorial" into main
diff --git a/quickstep/res/layout/redesigned_gesture_tutorial_fragment.xml b/quickstep/res/layout/redesigned_gesture_tutorial_fragment.xml
index b004dfd..7530c28 100644
--- a/quickstep/res/layout/redesigned_gesture_tutorial_fragment.xml
+++ b/quickstep/res/layout/redesigned_gesture_tutorial_fragment.xml
@@ -147,6 +147,7 @@
             android:layout_height="wrap_content"
             android:layout_marginTop="104dp"
             android:accessibilityHeading="true"
+            android:accessibilityTraversalBefore="@id/gesture_tutorial_fragment_feedback_subtitle"
             android:gravity="top"
             android:lineSpacingExtra="-1sp"
             android:textAppearance="@style/TextAppearance.GestureTutorial.MainTitle"
@@ -161,6 +162,8 @@
             android:layout_marginTop="24dp"
             android:lineSpacingExtra="4sp"
             android:textAppearance="@style/TextAppearance.GestureTutorial.MainSubtitle"
+            android:accessibilityTraversalAfter="@id/gesture_tutorial_fragment_feedback_title"
+            android:accessibilityTraversalBefore="@id/gesture_tutorial_fragment_action_button"
 
             app:layout_constraintStart_toStartOf="parent"
             app:layout_constraintTop_toBottomOf="@id/gesture_tutorial_fragment_feedback_title" />
@@ -224,6 +227,10 @@
         android:layout_marginBottom="@dimen/gesture_tutorial_done_button_bottom_margin"
         android:layout_alignParentBottom="true"
         android:layout_alignParentEnd="true"
+        android:clickable="true"
+        android:focusableInTouchMode="true"
+        android:accessibilityTraversalAfter="@id/gesture_tutorial_fragment_feedback_subtitle"
+        android:contentDescription="@string/gesture_tutorial_action_button_label"
         android:background="@drawable/gesture_tutorial_action_button_background"
         android:stateListAnimator="@null"
         android:text="@string/gesture_tutorial_action_button_label"
diff --git a/quickstep/src/com/android/quickstep/interaction/TutorialController.java b/quickstep/src/com/android/quickstep/interaction/TutorialController.java
index 7d14a3e..0fc95e2 100644
--- a/quickstep/src/com/android/quickstep/interaction/TutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/TutorialController.java
@@ -80,8 +80,8 @@
     private static final CharSequence DEFAULT_PIXEL_TIPS_APP_NAME = "Pixel Tips";
 
     private static final int FEEDBACK_ANIMATION_MS = 133;
-    private static final int RIPPLE_VISIBLE_MS = 300;
-    private static final int GESTURE_ANIMATION_DELAY_MS = 1500;
+    private static final int SUBTITLE_ANNOUNCE_DELAY_MS = 3000;
+    private static final int DONE_BUTTON_ANNOUNCE_DELAY_MS = 4000;
     private static final int ADVANCE_TUTORIAL_TIMEOUT_MS = 3000;
     private static final long GESTURE_ANIMATION_PAUSE_DURATION_MILLIS = 1000;
     protected float mExitingAppEndingCornerRadius;
@@ -124,10 +124,12 @@
     // These runnables  should be used when posting callbacks to their views and cleared from their
     // views before posting new callbacks.
     private final Runnable mTitleViewCallback;
+    private final Runnable mSubtitleViewCallback;
     @Nullable private Runnable mFeedbackViewCallback;
     @Nullable private Runnable mFakeTaskViewCallback;
     @Nullable private Runnable mFakeTaskbarViewCallback;
     private final Runnable mShowFeedbackRunnable;
+    private final AccessibilityManager mAccessibilityManager;
 
     TutorialController(TutorialFragment tutorialFragment, TutorialType tutorialType) {
         mTutorialFragment = tutorialFragment;
@@ -175,6 +177,7 @@
 
         mFeedbackTitleView.setText(getIntroductionTitle());
         mFeedbackSubtitleView.setText(getIntroductionSubtitle());
+
         mExitingAppView.setClipToOutline(true);
         mExitingAppView.setOutlineProvider(new ViewOutlineProvider() {
             @Override
@@ -183,8 +186,16 @@
             }
         });
 
-        mTitleViewCallback = () -> mFeedbackTitleView.sendAccessibilityEvent(
-                AccessibilityEvent.TYPE_VIEW_FOCUSED);
+        mAccessibilityManager = AccessibilityManager.getInstance(mContext);
+        mTitleViewCallback = () -> {
+            mFeedbackTitleView.requestFocus();
+            mFeedbackTitleView.sendAccessibilityEvent(
+                    AccessibilityEvent.TYPE_VIEW_FOCUSED);
+        };
+        mSubtitleViewCallback = () -> {
+            mFeedbackSubtitleView.requestFocus();
+            mFeedbackSubtitleView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
+        };
         mShowFeedbackRunnable = () -> {
             mFeedbackView.setAlpha(0f);
             mFeedbackView.setScaleX(0.95f);
@@ -203,10 +214,10 @@
                             mFeedbackViewCallback = mTutorialFragment::continueTutorial;
                             mFeedbackView.postDelayed(
                                     mFeedbackViewCallback,
-                                    AccessibilityManager.getInstance(mContext)
-                                            .getRecommendedTimeoutMillis(
-                                                    ADVANCE_TUTORIAL_TIMEOUT_MS,
-                                                    AccessibilityManager.FLAG_CONTENT_TEXT));
+                                    mAccessibilityManager.getRecommendedTimeoutMillis(
+                                            ADVANCE_TUTORIAL_TIMEOUT_MS,
+                                            AccessibilityManager.FLAG_CONTENT_TEXT
+                                                    | AccessibilityManager.FLAG_CONTENT_CONTROLS));
                         }
                     })
                     .start();
@@ -404,6 +415,7 @@
             int subtitleResId,
             boolean isGestureSuccessful) {
         mFeedbackTitleView.removeCallbacks(mTitleViewCallback);
+        mFeedbackSubtitleView.removeCallbacks(mSubtitleViewCallback);
         if (mFeedbackViewCallback != null) {
             mFeedbackView.removeCallbacks(mFeedbackViewCallback);
             mFeedbackViewCallback = null;
@@ -411,6 +423,15 @@
 
         mFeedbackTitleView.setText(titleResId);
         mFeedbackSubtitleView.setText(subtitleResId);
+        mFeedbackTitleView.postDelayed(mTitleViewCallback, mAccessibilityManager
+                .getRecommendedTimeoutMillis(
+                        FEEDBACK_ANIMATION_MS,
+                        AccessibilityManager.FLAG_CONTENT_TEXT));
+        mFeedbackSubtitleView.postDelayed(mSubtitleViewCallback, mAccessibilityManager
+                .getRecommendedTimeoutMillis(
+                        SUBTITLE_ANNOUNCE_DELAY_MS,
+                        AccessibilityManager.FLAG_CONTENT_TEXT));
+
         if (isGestureSuccessful) {
             if (mTutorialFragment.isAtFinalStep()) {
                 showActionButton();
@@ -467,6 +488,7 @@
             mFakeTaskbarViewCallback = null;
         }
         mFeedbackTitleView.removeCallbacks(mTitleViewCallback);
+        mFeedbackSubtitleView.removeCallbacks(mSubtitleViewCallback);
     }
 
     private void playFeedbackAnimation() {
@@ -542,6 +564,13 @@
         mSkipButton.setVisibility(GONE);
         mDoneButton.setVisibility(View.VISIBLE);
         mDoneButton.setOnClickListener(this::onActionButtonClicked);
+        mDoneButton.postDelayed(() -> {
+            mDoneButton.requestFocus();
+            mDoneButton.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED);
+        }, mAccessibilityManager
+                .getRecommendedTimeoutMillis(
+                        DONE_BUTTON_ANNOUNCE_DELAY_MS,
+                        AccessibilityManager.FLAG_CONTENT_CONTROLS));
     }
 
     void hideFakeTaskbar(boolean animateToHotseat) {