From c17c3171c5977fd4da814d3e7e2e03855ae8b91b Mon Sep 17 00:00:00 2001 From: Andy Wickham Date: Mon, 3 Oct 2022 20:49:32 -0700 Subject: [PATCH] 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 --- .../allapps/SearchTransitionController.java | 105 ++++++++++-------- 1 file changed, 58 insertions(+), 47 deletions(-) diff --git a/src/com/android/launcher3/allapps/SearchTransitionController.java b/src/com/android/launcher3/allapps/SearchTransitionController.java index bde4fa6e37..9c3dab4ec3 100644 --- a/src/com/android/launcher3/allapps/SearchTransitionController.java +++ b/src/com/android/launcher3/allapps/SearchTransitionController.java @@ -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,67 +190,72 @@ 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; - } - - // Adjust content alpha based on start progress and stagger. - float startContentFadeProgress = Math.max(0, - 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)); - - // Adjust background (or decorator) alpha based on start progress and stagger. - float startBackgroundFadeProgress = Math.max(0, - TOP_BACKGROUND_FADE_PROGRESS_START - - CONTENT_STAGGER * numSearchResultsAnimated); - float endBackgroundFadeProgress = Math.min(1, - startBackgroundFadeProgress + BACKGROUND_FADE_PROGRESS_DURATION); - float 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). - Drawable background = searchResultView.getBackground(); - if (background != null) { - background.setAlpha((int) (255 * backgroundAlpha)); + 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); + float endContentFadeProgress = Math.min(1, + startContentFadeProgress + CONTENT_FADE_PROGRESS_DURATION); + contentAlpha = 1 - clampToProgress(mSearchToAzProgress, + startContentFadeProgress, endContentFadeProgress); + + // Adjust background (or decorator) alpha based on start progress and stagger. + float startBackgroundFadeProgress = Math.max(0, + TOP_BACKGROUND_FADE_PROGRESS_START + - CONTENT_STAGGER * numSearchResultsAnimated); + float endBackgroundFadeProgress = Math.min(1, + startBackgroundFadeProgress + BACKGROUND_FADE_PROGRESS_DURATION); + backgroundAlpha = 1 - clampToProgress(mSearchToAzProgress, + startBackgroundFadeProgress, endBackgroundFadeProgress); + + 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.