Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c17c3171 authored by Andy Wickham's avatar Andy Wickham
Browse files

More robust fix to BubbleTextViews appearing on multiple rows.

This is the more comprehensive version of ag/20119299.
Improvements compared to that change:
 - Icons on the same row animate together (as opposed to the
   first icon on the row animating separately)
 - Multiple rows of predicted apps are supported (any beyond
   the first row are animated like everything else)

--- Original description ---

Example BubbleTextView: WhatsApp/Gmail conversation shortcuts.

The issue was we were treating these the same as the top app
row, but we were assuming there would only be 1 such row, which
messed up the measurement logic. At the same time, the logic
specific to that app row was redundant with the new logic for
rows containing mulitple items.

This solution does 2 things:
 - Removes special logic for app row (it now uses the same
   logic as other rows with multiple items, i.e. uses the span
   index to determine the height of the row)
 - Keeps the scale/alpha at 1 for the first row of app icons.
   This currently only applies to predicted apps, but if there
   were multiple app rows in the future, the additional rows
   would animate the same way as other rows (see demo videos
   for an example with double predicted apps in 0 state). In
   the conversation case, the other icons are deep shortcuts.

The result is the app row still does what it did before (stays
fixed at full size/opacity), and deep shortcuts like the ones
used for WhatsApp and Gmail animate like other rows of items,
such as screenshots.

Demo videos: https://drive.google.com/drive/folders/1GPQNIwMfuj9ZdAbRrh-K75C5xJYT4Gzo?resourcekey=0-ojO6VGetEBy5YTq4roFmlw&usp=sharing

Test: Manual with and without inject_web_top (which moves app row)
for WhatsApp and Gmail with AiAi fishfood.
Bug: 239927522

Change-Id: Ib2ca97b93798cb57eb55545eeba8be9322484f7d
parent 126d1783
Loading
Loading
Loading
Loading
+58 −47
Original line number Diff line number Diff line
@@ -170,12 +170,13 @@ public class SearchTransitionController {
    /**
     * Updates the children views of SearchRecyclerView based on the current animation progress.
     *
     * @return the total height of animating views (excluding any app icons).
     * @return the total height of animating views (excluding at most one row of app icons).
     */
    private int updateSearchRecyclerViewProgress() {
        int numSearchResultsAnimated = 0;
        int totalHeight = 0;
        int appRowHeight = 0;
        boolean appRowComplete = false;
        Integer top = null;
        SearchRecyclerView searchRecyclerView = getSearchRecyclerView();

@@ -189,30 +190,29 @@ public class SearchTransitionController {
                top = searchResultView.getTop();
            }

            if (searchResultView instanceof BubbleTextView
                    && searchResultView.getTag() instanceof ItemInfo
                    && ((ItemInfo) searchResultView.getTag()).itemType == ITEM_TYPE_APPLICATION) {
                // The first app icon will set appRowHeight, which will also contribute to
                // totalHeight. Additional app icons should remove the appRowHeight to remain in
                // the same row as the first app.
                searchResultView.setY(top + totalHeight - appRowHeight);
                if (appRowHeight == 0) {
                    appRowHeight = searchResultView.getHeight();
                    totalHeight += appRowHeight;
                }
                // Don't scale/fade app row.
                searchResultView.setScaleY(1);
                searchResultView.setAlpha(1);
                continue;
            int adapterPosition = searchRecyclerView.getChildAdapterPosition(searchResultView);
            int spanIndex = getSpanIndex(searchRecyclerView, adapterPosition);
            appRowComplete |= appRowHeight > 0 && spanIndex == 0;
            // We don't animate the first (currently only) app row we see, as that is assumed to be
            // predicted/prefix-matched apps.
            boolean shouldAnimate = !isAppIcon(searchResultView) || appRowComplete;

            float contentAlpha = 1f;
            float backgroundAlpha = 1f;
            if (shouldAnimate) {
                if (spanIndex > 0) {
                    // Animate this item with the previous item on the same row.
                    numSearchResultsAnimated--;
                }

                // Adjust content alpha based on start progress and stagger.
                float startContentFadeProgress = Math.max(0,
                    TOP_CONTENT_FADE_PROGRESS_START - CONTENT_STAGGER * numSearchResultsAnimated);
                        TOP_CONTENT_FADE_PROGRESS_START
                                - CONTENT_STAGGER * numSearchResultsAnimated);
                float endContentFadeProgress = Math.min(1,
                        startContentFadeProgress + CONTENT_FADE_PROGRESS_DURATION);
            searchResultView.setAlpha(1 - clampToProgress(mSearchToAzProgress,
                    startContentFadeProgress, endContentFadeProgress));
                contentAlpha = 1 - clampToProgress(mSearchToAzProgress,
                        startContentFadeProgress, endContentFadeProgress);

                // Adjust background (or decorator) alpha based on start progress and stagger.
                float startBackgroundFadeProgress = Math.max(0,
@@ -220,36 +220,42 @@ public class SearchTransitionController {
                                - CONTENT_STAGGER * numSearchResultsAnimated);
                float endBackgroundFadeProgress = Math.min(1,
                        startBackgroundFadeProgress + BACKGROUND_FADE_PROGRESS_DURATION);
            float backgroundAlpha = 1 - clampToProgress(mSearchToAzProgress,
                backgroundAlpha = 1 - clampToProgress(mSearchToAzProgress,
                        startBackgroundFadeProgress, endBackgroundFadeProgress);
            int adapterPosition = searchRecyclerView.getChildAdapterPosition(searchResultView);
            boolean decoratorFilled =
                    adapterPosition != NO_POSITION
                            && searchRecyclerView.getApps().getAdapterItems().get(adapterPosition)
                            .setDecorationFillAlpha((int) (255 * backgroundAlpha));
            if (!decoratorFilled) {
                // Try to adjust background alpha instead (e.g. for Search Edu card).

                numSearchResultsAnimated++;
            }
            searchResultView.setAlpha(contentAlpha);
            // Apply background alpha to decorator if possible.
            if (adapterPosition != NO_POSITION) {
                searchRecyclerView.getApps().getAdapterItems()
                        .get(adapterPosition).setDecorationFillAlpha((int) (255 * backgroundAlpha));
            }
            // Apply background alpha to view's background (e.g. for Search Edu card).
            Drawable background = searchResultView.getBackground();
            if (background != null) {
                background.setAlpha((int) (255 * backgroundAlpha));
            }
            }

            float scaleY = 1 - mSearchToAzProgress;
            float scaleY = 1;
            if (shouldAnimate) {
                scaleY = 1 - mSearchToAzProgress;
            }
            int scaledHeight = (int) (searchResultView.getHeight() * scaleY);
            searchResultView.setScaleY(scaleY);

            // For rows with multiple elements, only count the height once and translate elements to
            // the same y position.
            int y = top + totalHeight;
            int spanIndex = getSpanIndex(searchRecyclerView, adapterPosition);
            if (spanIndex > 0) {
                // Continuation of an existing row; move this item into the row.
                y -= scaledHeight;
            } else {
                // Start of a new row contributes to total height and animation stagger.
                numSearchResultsAnimated++;
                // Start of a new row contributes to total height.
                totalHeight += scaledHeight;
                if (!shouldAnimate) {
                    appRowHeight = scaledHeight;
                }
            }
            searchResultView.setY(y);
        }
@@ -275,6 +281,11 @@ public class SearchTransitionController {
        return adapter.getSpanIndex(adapterPosition);
    }

    private boolean isAppIcon(View item) {
        return item instanceof BubbleTextView && item.getTag() instanceof ItemInfo
                && ((ItemInfo) item.getTag()).itemType == ITEM_TYPE_APPLICATION;
    }

    /** Called just before a child is attached to the SearchRecyclerView. */
    private void onSearchChildAttached(View child) {
        // Avoid allocating hardware layers for alpha changes.