From acdf07e0b7c1562f10b9ba2840b5bbc2b2de04c6 Mon Sep 17 00:00:00 2001 From: Jon Miranda Date: Tue, 7 Mar 2023 08:03:20 -0800 Subject: [PATCH] Hide taskbar view for app open/close animation. Bug: 246635237 Test: open app in hotseat close app in hotseat the 'matching' view in taskbar should be hidden tested icon, predicted icon, folders in taskbar/hotseat Change-Id: I74382480826afafe6ae58e78faf26fe10812e29b --- .../launcher3/QuickstepTransitionManager.java | 8 ++++- .../taskbar/TaskbarUIController.java | 28 ++++++++++++++++ .../quickstep/LauncherSwipeHandlerV2.java | 3 ++ .../launcher3/views/FloatingIconView.java | 33 ++++++++++++++----- 4 files changed, 62 insertions(+), 10 deletions(-) diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java index 5ddf2a89e7..ea7eba3e8b 100644 --- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java +++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java @@ -634,7 +634,10 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener boolean appTargetsAreTranslucent = areAllTargetsTranslucent(appTargets); RectF launcherIconBounds = new RectF(); - FloatingIconView floatingView = FloatingIconView.getFloatingIconView(mLauncher, v, + FloatingIconView floatingView = getFloatingIconView(mLauncher, v, + mLauncher.getTaskbarUIController() == null + ? null + : mLauncher.getTaskbarUIController().findMatchingView(v), !appTargetsAreTranslucent, launcherIconBounds, true /* isOpening */); Rect crop = new Rect(); Matrix matrix = new Matrix(); @@ -1350,6 +1353,9 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener isTransluscent, fallbackBackgroundColor); } else if (launcherView != null) { floatingIconView = getFloatingIconView(mLauncher, launcherView, + mLauncher.getTaskbarUIController() == null + ? null + : mLauncher.getTaskbarUIController().findMatchingView(launcherView), true /* hideOriginal */, targetRect, false /* isOpening */); } else { targetRect.set(getDefaultWindowTargetRect()); diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java index b552e9bd18..13f0405c43 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java @@ -17,6 +17,8 @@ package com.android.launcher3.taskbar; import static android.app.ActivityTaskManager.INVALID_TASK_ID; +import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT; +import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION; import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_IN_APP; import android.content.Intent; @@ -277,4 +279,30 @@ public class TaskbarUIController { * No-op if the view is not yet open. */ public void launchSplitTasks(@NonNull View taskview, @NonNull GroupTask groupTask) { } + + /** + * Returns the matching view (if any) in the taskbar. + * @param view The view to match. + */ + public @Nullable View findMatchingView(View view) { + if (!(view.getTag() instanceof ItemInfo)) { + return null; + } + ItemInfo info = (ItemInfo) view.getTag(); + if (info.container != CONTAINER_HOTSEAT && info.container != CONTAINER_HOTSEAT_PREDICTION) { + return null; + } + + // Taskbar has the same items as the hotseat and we can use screenId to find the match. + int screenId = info.screenId; + View[] views = mControllers.taskbarViewController.getIconViews(); + for (int i = views.length - 1; i >= 0; --i) { + if (views[i] != null + && views[i].getTag() instanceof ItemInfo + && ((ItemInfo) views[i].getTag()).screenId == screenId) { + return views[i]; + } + } + return null; + } } diff --git a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java index bb781c82b7..315137441e 100644 --- a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java +++ b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java @@ -105,6 +105,9 @@ public class LauncherSwipeHandlerV2 extends private HomeAnimationFactory createIconHomeAnimationFactory(View workspaceView) { RectF iconLocation = new RectF(); FloatingIconView floatingIconView = getFloatingIconView(mActivity, workspaceView, + mActivity.getTaskbarUIController() == null + ? null + : mActivity.getTaskbarUIController().findMatchingView(workspaceView), true /* hideOriginal */, iconLocation, false /* isOpening */); // We want the window alpha to be 0 once this threshold is met, so that the diff --git a/src/com/android/launcher3/views/FloatingIconView.java b/src/com/android/launcher3/views/FloatingIconView.java index 55af6221d8..e233e4643a 100644 --- a/src/com/android/launcher3/views/FloatingIconView.java +++ b/src/com/android/launcher3/views/FloatingIconView.java @@ -95,6 +95,9 @@ public class FloatingIconView extends FrameLayout implements private ClipIconView mClipIconView; private @Nullable Drawable mBadge; + // A view whose visibility should update in sync with mOriginalIcon. + private @Nullable View mMatchVisibilityView; + private View mOriginalIcon; private RectF mPositionOut; private Runnable mOnTargetChangeRunnable; @@ -386,7 +389,7 @@ public class FloatingIconView extends FrameLayout implements * Checks if the icon result is loaded. If true, we set the icon immediately. Else, we add a * callback to set the icon once the icon result is loaded. */ - private void checkIconResult(View originalView) { + private void checkIconResult() { CancellationSignal cancellationSignal = new CancellationSignal(); if (mIconLoadResult == null) { @@ -399,7 +402,7 @@ public class FloatingIconView extends FrameLayout implements setIcon(mIconLoadResult.drawable, mIconLoadResult.badge, mIconLoadResult.btvDrawable, mIconLoadResult.iconOffset); setVisibility(VISIBLE); - setIconAndDotVisible(originalView, false); + updateViewsVisibility(false /* isVisible */); } else { mIconLoadResult.onIconLoaded = () -> { if (cancellationSignal.isCanceled()) { @@ -410,7 +413,7 @@ public class FloatingIconView extends FrameLayout implements mIconLoadResult.btvDrawable, mIconLoadResult.iconOffset); setVisibility(VISIBLE); - setIconAndDotVisible(originalView, false); + updateViewsVisibility(false /* isVisible */); }; mLoadIconSignal = cancellationSignal; } @@ -481,9 +484,9 @@ public class FloatingIconView extends FrameLayout implements // No need to wait for icon load since we can display the BubbleTextView drawable. setVisibility(View.VISIBLE); } - if (!mIsOpening && mOriginalIcon != null) { + if (!mIsOpening) { // When closing an app, we want the item on the workspace to be invisible immediately - setIconAndDotVisible(mOriginalIcon, false); + updateViewsVisibility(false /* isVisible */); } } @@ -562,13 +565,14 @@ public class FloatingIconView extends FrameLayout implements /** * Creates a floating icon view for {@param originalView}. * @param originalView The view to copy + * @param secondView A view whose visibility should update in sync with originalView. * @param hideOriginal If true, it will hide {@param originalView} while this view is visible. * Else, we will not draw anything in this view. * @param positionOut Rect that will hold the size and position of v. * @param isOpening True if this view replaces the icon for app open animation. */ public static FloatingIconView getFloatingIconView(Launcher launcher, View originalView, - boolean hideOriginal, RectF positionOut, boolean isOpening) { + @Nullable View secondView, boolean hideOriginal, RectF positionOut, boolean isOpening) { final DragLayer dragLayer = launcher.getDragLayer(); ViewGroup parent = (ViewGroup) dragLayer.getParent(); FloatingIconView view = launcher.getViewCache().getView(R.layout.floating_icon_view, @@ -578,6 +582,7 @@ public class FloatingIconView extends FrameLayout implements // Init properties before getting the drawable. view.mIsOpening = isOpening; view.mOriginalIcon = originalView; + view.mMatchVisibilityView = secondView; view.mPositionOut = positionOut; // Get the drawable on the background thread @@ -597,7 +602,8 @@ public class FloatingIconView extends FrameLayout implements view.matchPositionOf(launcher, originalView, isOpening, positionOut); // We need to add it to the overlay, but keep it invisible until animation starts.. - setIconAndDotVisible(view, false); + view.setVisibility(View.INVISIBLE); + parent.addView(view); dragLayer.addView(view.mListenerView); view.mListenerView.setListener(view::fastFinish); @@ -606,7 +612,7 @@ public class FloatingIconView extends FrameLayout implements view.mEndRunnable = null; if (hideOriginal) { - setIconAndDotVisible(originalView, true); + view.updateViewsVisibility(true /* isVisible */); view.finish(dragLayer); } else { view.finish(dragLayer); @@ -617,12 +623,21 @@ public class FloatingIconView extends FrameLayout implements // Must be called after the fastFinish listener and end runnable is created so that // the icon is not left in a hidden state. if (shouldLoadIcon) { - view.checkIconResult(originalView); + view.checkIconResult(); } return view; } + private void updateViewsVisibility(boolean isVisible) { + if (mOriginalIcon != null) { + setIconAndDotVisible(mOriginalIcon, isVisible); + } + if (mMatchVisibilityView != null) { + setIconAndDotVisible(mMatchVisibilityView, isVisible); + } + } + private void finish(DragLayer dragLayer) { ((ViewGroup) dragLayer.getParent()).removeView(this); dragLayer.removeView(mListenerView);