Focus on the right pane when choosing an app on left

As before, user can also do 4-finger swipe down to move to right pane.

Bug: 345396938
Flag: EXEMPT bugfix
Test: Manual - see video in comments
Change-Id: If72862af2b05ae54c47e8d446a168252d3fc8194
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListItemAnimator.java b/src/com/android/launcher3/widget/picker/WidgetsListItemAnimator.java
index 854700f..6a1921e 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsListItemAnimator.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsListItemAnimator.java
@@ -16,6 +16,8 @@
 
 package com.android.launcher3.widget.picker;
 
+import static android.animation.ValueAnimator.areAnimatorsEnabled;
+
 import static com.android.launcher3.widget.picker.WidgetsListAdapter.VIEW_TYPE_WIDGETS_LIST;
 
 import androidx.recyclerview.widget.DefaultItemAnimator;
@@ -26,6 +28,14 @@
     public static final int MOVE_DURATION_MS = 90;
     public static final int ADD_DURATION_MS = 120;
 
+    // DefaultItemAnimator runs change and move animations before running add animations (i.e.
+    // before expanded list item's content start animating to become visible on screen).
+    public static final int WIDGET_LIST_ITEM_APPEARANCE_START_DELAY =
+            areAnimatorsEnabled() ? (CHANGE_DURATION_MS + MOVE_DURATION_MS) : 0;
+    // Delay after which all item animations are ran and list item's content is visible.
+    public static final int WIDGET_LIST_ITEM_APPEARANCE_DELAY =
+            WIDGET_LIST_ITEM_APPEARANCE_START_DELAY + ADD_DURATION_MS;
+
     public WidgetsListItemAnimator() {
         super();
 
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java b/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java
index 45d733a..679b0f5 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java
@@ -15,10 +15,7 @@
  */
 package com.android.launcher3.widget.picker;
 
-import static com.android.launcher3.widget.picker.WidgetsListItemAnimator.CHANGE_DURATION_MS;
-import static com.android.launcher3.widget.picker.WidgetsListItemAnimator.MOVE_DURATION_MS;
-
-import static android.animation.ValueAnimator.areAnimatorsEnabled;
+import static com.android.launcher3.widget.picker.WidgetsListItemAnimator.WIDGET_LIST_ITEM_APPEARANCE_START_DELAY;
 
 import android.content.Context;
 import android.graphics.Bitmap;
@@ -157,8 +154,7 @@
             // Pass resize delay to let the "move" and "change" animations run before resizing the
             // row.
             tableRow.setupRow(widgetItems.size(),
-                    /*resizeDelayMs=*/
-                    areAnimatorsEnabled() ? (CHANGE_DURATION_MS + MOVE_DURATION_MS) : 0);
+                    /*resizeDelayMs=*/ WIDGET_LIST_ITEM_APPEARANCE_START_DELAY);
             if (tableRow.getChildCount() > widgetItems.size()) {
                 for (int j = widgetItems.size(); j < tableRow.getChildCount(); j++) {
                     tableRow.getChildAt(j).setVisibility(View.GONE);
diff --git a/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java b/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java
index 5d71db6..ae8b5db 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java
@@ -21,6 +21,7 @@
 import static com.android.launcher3.UtilitiesKt.CLIP_TO_PADDING_FALSE_MODIFIER;
 import static com.android.launcher3.UtilitiesKt.modifyAttributesOnViewTree;
 import static com.android.launcher3.UtilitiesKt.restoreAttributesOnViewTree;
+import static com.android.launcher3.widget.picker.WidgetsListItemAnimator.WIDGET_LIST_ITEM_APPEARANCE_DELAY;
 
 import android.content.Context;
 import android.graphics.Rect;
@@ -31,6 +32,7 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewParent;
+import android.view.accessibility.AccessibilityNodeInfo;
 import android.widget.FrameLayout;
 import android.widget.LinearLayout;
 import android.widget.ScrollView;
@@ -281,10 +283,19 @@
             mRightPane.removeAllViews();
             mRightPane.addView(mWidgetRecommendationsContainer);
             mRightPaneScrollView.setScrollY(0);
-            mRightPane.setAccessibilityPaneTitle(suggestionsRightPaneTitle);
             mSuggestedWidgetsPackageUserKey = PackageUserKey.fromPackageItemInfo(packageItemInfo);
             final boolean isChangingHeaders = mSelectedHeader == null
                     || !mSelectedHeader.equals(mSuggestedWidgetsPackageUserKey);
+            // If the initial focus view is still focused, it is likely a programmatic header
+            // click.
+            if (mSelectedHeader != null
+                    && !getAccessibilityInitialFocusView().isAccessibilityFocused()) {
+                post(() -> {
+                    mRightPaneScrollView.setAccessibilityPaneTitle(suggestionsRightPaneTitle);
+                    mRightPaneScrollView.performAccessibilityAction(
+                            AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null);
+                });
+            }
             if (isChangingHeaders)  {
                 // If switching from another header, unselect any WidgetCells. This is necessary
                 // because we do not clear/recycle the WidgetCells in the recommendations container
@@ -296,7 +307,6 @@
             mSelectedHeader = mSuggestedWidgetsPackageUserKey;
         });
         mSuggestedWidgetsContainer.addView(mSuggestedWidgetsHeader);
-        mRightPane.setAccessibilityPaneTitle(suggestionsRightPaneTitle);
     }
 
     @Override
@@ -323,12 +333,14 @@
 
         mActivePage = currentActivePage;
 
-        if (mSuggestedWidgetsHeader == null) {
-            mAdapters.get(currentActivePage).mWidgetsListAdapter.selectFirstHeaderEntry();
-            mAdapters.get(currentActivePage).mWidgetsRecyclerView.scrollToTop();
-        } else if (currentActivePage == PERSONAL_TAB || currentActivePage == WORK_TAB) {
-            mSuggestedWidgetsHeader.callOnClick();
-        }
+        // When using talkback, swiping left while on right pane, should navigate to the widgets
+        // list on left.
+        mAdapters.get(mActivePage).mWidgetsRecyclerView.setAccessibilityTraversalBefore(
+                mRightPaneScrollView.getId());
+
+        // On page change, select the first item in the list to show in the right pane.
+        mAdapters.get(currentActivePage).mWidgetsListAdapter.selectFirstHeaderEntry();
+        mAdapters.get(currentActivePage).mWidgetsRecyclerView.scrollToTop();
     }
 
     @Override
@@ -383,6 +395,10 @@
             public void onHeaderChanged(@NonNull PackageUserKey selectedHeader) {
                 final boolean isSameHeader = mSelectedHeader != null
                         && mSelectedHeader.equals(selectedHeader);
+                // If the initial focus view is still focused, it is likely a programmatic header
+                // click.
+                final boolean isUserClick = mSelectedHeader != null
+                        && !getAccessibilityInitialFocusView().isAccessibilityFocused();
                 mSelectedHeader = selectedHeader;
                 WidgetsListContentEntry contentEntry = mActivityContext.getPopupDataProvider()
                         .getSelectedAppWidgets(selectedHeader);
@@ -427,11 +443,14 @@
                 };
                 mRightPane.removeAllViews();
                 mRightPane.addView(widgetsRowViewHolder.itemView);
+                if (isUserClick) {
+                    mRightPaneScrollView.setAccessibilityPaneTitle(getContext().getString(
+                            R.string.widget_picker_right_pane_accessibility_title,
+                            contentEntry.mPkgItem.title));
+                    postDelayed(() -> focusOnFirstWidgetCell(widgetsRowViewHolder.tableContainer),
+                            WIDGET_LIST_ITEM_APPEARANCE_DELAY);
+                }
                 mRightPaneScrollView.setScrollY(0);
-                mRightPane.setAccessibilityPaneTitle(
-                        getContext().getString(
-                                R.string.widget_picker_right_pane_accessibility_title,
-                                contentEntry.mPkgItem.title));
             }
         };
     }
@@ -445,6 +464,18 @@
         }
     }
 
+    /**
+     * Requests focus on the first widget cell in the given widget section.
+     */
+    private static void focusOnFirstWidgetCell(ViewGroup parent) {
+        if (parent == null) return;
+        WidgetCell cell = Utilities.findViewByPredicate(parent, v -> v instanceof WidgetCell);
+        if (cell != null) {
+            cell.performAccessibilityAction(
+                    AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null);
+        }
+    }
+
     private static void unselectWidgetCell(ViewGroup parent, WidgetItem item) {
         if (parent == null || item == null) return;
         WidgetCell cell = Utilities.findViewByPredicate(parent, v -> v instanceof WidgetCell wc