Loading src/com/android/launcher3/widget/picker/WidgetsListItemAnimator.java +10 −0 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -26,6 +28,14 @@ public class WidgetsListItemAnimator extends DefaultItemAnimator { 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(); Loading src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java +2 −6 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -157,8 +154,7 @@ public final class WidgetsListTableViewHolderBinder // 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); Loading src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java +43 −12 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import static com.android.launcher3.UtilitiesKt.CLIP_CHILDREN_FALSE_MODIFIER; 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; Loading @@ -31,6 +32,7 @@ import android.view.MotionEvent; 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; Loading Loading @@ -281,10 +283,19 @@ public class WidgetsTwoPaneSheet extends WidgetsFullSheet { 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 Loading @@ -296,7 +307,6 @@ public class WidgetsTwoPaneSheet extends WidgetsFullSheet { mSelectedHeader = mSuggestedWidgetsPackageUserKey; }); mSuggestedWidgetsContainer.addView(mSuggestedWidgetsHeader); mRightPane.setAccessibilityPaneTitle(suggestionsRightPaneTitle); } @Override Loading @@ -323,12 +333,14 @@ public class WidgetsTwoPaneSheet extends WidgetsFullSheet { mActivePage = currentActivePage; if (mSuggestedWidgetsHeader == null) { // 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(); } else if (currentActivePage == PERSONAL_TAB || currentActivePage == WORK_TAB) { mSuggestedWidgetsHeader.callOnClick(); } } @Override Loading Loading @@ -383,6 +395,10 @@ public class WidgetsTwoPaneSheet extends WidgetsFullSheet { 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); Loading Loading @@ -427,11 +443,14 @@ public class WidgetsTwoPaneSheet extends WidgetsFullSheet { }; mRightPane.removeAllViews(); mRightPane.addView(widgetsRowViewHolder.itemView); mRightPaneScrollView.setScrollY(0); mRightPane.setAccessibilityPaneTitle( getContext().getString( 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); } }; } Loading @@ -445,6 +464,18 @@ public class WidgetsTwoPaneSheet extends WidgetsFullSheet { } } /** * 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 Loading Loading
src/com/android/launcher3/widget/picker/WidgetsListItemAnimator.java +10 −0 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -26,6 +28,14 @@ public class WidgetsListItemAnimator extends DefaultItemAnimator { 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(); Loading
src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java +2 −6 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -157,8 +154,7 @@ public final class WidgetsListTableViewHolderBinder // 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); Loading
src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java +43 −12 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import static com.android.launcher3.UtilitiesKt.CLIP_CHILDREN_FALSE_MODIFIER; 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; Loading @@ -31,6 +32,7 @@ import android.view.MotionEvent; 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; Loading Loading @@ -281,10 +283,19 @@ public class WidgetsTwoPaneSheet extends WidgetsFullSheet { 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 Loading @@ -296,7 +307,6 @@ public class WidgetsTwoPaneSheet extends WidgetsFullSheet { mSelectedHeader = mSuggestedWidgetsPackageUserKey; }); mSuggestedWidgetsContainer.addView(mSuggestedWidgetsHeader); mRightPane.setAccessibilityPaneTitle(suggestionsRightPaneTitle); } @Override Loading @@ -323,12 +333,14 @@ public class WidgetsTwoPaneSheet extends WidgetsFullSheet { mActivePage = currentActivePage; if (mSuggestedWidgetsHeader == null) { // 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(); } else if (currentActivePage == PERSONAL_TAB || currentActivePage == WORK_TAB) { mSuggestedWidgetsHeader.callOnClick(); } } @Override Loading Loading @@ -383,6 +395,10 @@ public class WidgetsTwoPaneSheet extends WidgetsFullSheet { 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); Loading Loading @@ -427,11 +443,14 @@ public class WidgetsTwoPaneSheet extends WidgetsFullSheet { }; mRightPane.removeAllViews(); mRightPane.addView(widgetsRowViewHolder.itemView); mRightPaneScrollView.setScrollY(0); mRightPane.setAccessibilityPaneTitle( getContext().getString( 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); } }; } Loading @@ -445,6 +464,18 @@ public class WidgetsTwoPaneSheet extends WidgetsFullSheet { } } /** * 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 Loading