diff options
author | 2025-03-20 13:40:29 -0700 | |
---|---|---|
committer | 2025-03-20 13:40:29 -0700 | |
commit | c12d67c4e07f01b562e6dba64c925347d3645985 (patch) | |
tree | 93e5d78746b49a6ec636c86b7165d42fa269e9a7 /quickstep/src | |
parent | 0d5889118714cf4ab86563309e34822515e413c6 (diff) | |
parent | 6ddfa5dfd5e5860de3bdaf7b2c887b6b49c674e2 (diff) |
Merge "Drag and drop from the search view on the overview screen." into main
Diffstat (limited to 'quickstep/src')
7 files changed, 255 insertions, 78 deletions
diff --git a/quickstep/src/com/android/launcher3/taskbar/BarsLocationAnimatorHelper.kt b/quickstep/src/com/android/launcher3/taskbar/BarsLocationAnimatorHelper.kt index b8060e1792..ad847b47ee 100644 --- a/quickstep/src/com/android/launcher3/taskbar/BarsLocationAnimatorHelper.kt +++ b/quickstep/src/com/android/launcher3/taskbar/BarsLocationAnimatorHelper.kt @@ -20,6 +20,7 @@ import android.animation.Animator import android.animation.AnimatorSet import android.animation.ObjectAnimator import android.animation.ValueAnimator +import android.content.Context import android.view.View import androidx.dynamicanimation.animation.SpringForce import com.android.app.animation.Interpolators @@ -30,11 +31,10 @@ import com.android.wm.shell.shared.bubbles.BubbleBarLocation /** Animator helper that creates bars animators. */ object BarsLocationAnimatorHelper { - - private const val FADE_OUT_ANIM_ALPHA_DURATION_MS: Long = 50L - private const val FADE_OUT_ANIM_ALPHA_DELAY_MS: Long = 50L - private const val FADE_OUT_ANIM_POSITION_DURATION_MS: Long = 100L - private const val FADE_IN_ANIM_ALPHA_DURATION_MS: Long = 100L + const val FADE_OUT_ANIM_ALPHA_DURATION_MS: Long = 50L + const val FADE_OUT_ANIM_ALPHA_DELAY_MS: Long = 50L + const val FADE_OUT_ANIM_POSITION_DURATION_MS: Long = 100L + const val FADE_IN_ANIM_ALPHA_DURATION_MS: Long = 100L // Use STIFFNESS_MEDIUMLOW which is not defined in the API constants private const val FADE_IN_ANIM_POSITION_SPRING_STIFFNESS: Float = 400f @@ -45,13 +45,13 @@ object BarsLocationAnimatorHelper { // During fade in animation we shift the bubble bar 1/60th of the screen width private const val FADE_IN_ANIM_POSITION_SHIFT: Float = 1 / 60f - private val View.screenWidth: Int + private val Context.screenWidth: Int get() = resources.displayMetrics.widthPixels - private val View.outShift: Float + val Context.outShift: Float get() = screenWidth * FADE_OUT_ANIM_POSITION_SHIFT - private val View.inShiftX: Float + val Context.inShiftX: Float get() = screenWidth * FADE_IN_ANIM_POSITION_SHIFT /** @@ -108,7 +108,7 @@ object BarsLocationAnimatorHelper { targetViewAlphaAnim: ObjectAnimator, bubbleBarView: View, ): Animator { - val shift: Float = bubbleBarView.outShift + val shift: Float = bubbleBarView.context.outShift val onLeft = newLocation.isOnLeft(bubbleBarView.isLayoutRtl) val startTx: Float @@ -132,15 +132,19 @@ object BarsLocationAnimatorHelper { return createLocationInAnimator(startTx, finalTx, targetViewAlphaAnim, bubbleBarView) } - /** Creates an animator for the bubble bar view out part. */ + /** + * Creates an animator for the bubble bar view out part. + * + * @param targetLocation the location bubble bar should animate to. + */ @JvmStatic fun getBubbleBarLocationOutAnimator( bubbleBarView: View, - bubbleBarLocation: BubbleBarLocation, + targetLocation: BubbleBarLocation, targetViewAlphaAnim: ObjectAnimator, ): Animator { - val onLeft = bubbleBarLocation.isOnLeft(bubbleBarView.isLayoutRtl) - val shift = bubbleBarView.outShift + val onLeft = targetLocation.isOnLeft(bubbleBarView.isLayoutRtl) + val shift = bubbleBarView.context.outShift val finalTx = bubbleBarView.translationX + (if (onLeft) -shift else shift) return this.createLocationOutAnimator(finalTx, targetViewAlphaAnim, bubbleBarView) } @@ -152,7 +156,7 @@ object BarsLocationAnimatorHelper { navButtonsView: View, navBarTargetTranslationX: Float, ): Animator { - val outShift: Float = navButtonsView.outShift + val outShift: Float = navButtonsView.context.outShift val isNavBarOnRight: Boolean = location.isOnLeft(navButtonsView.isLayoutRtl) val finalOutTx = navButtonsView.translationX + (if (isNavBarOnRight) outShift else -outShift) @@ -162,7 +166,7 @@ object BarsLocationAnimatorHelper { ObjectAnimator.ofFloat(navButtonsView, LauncherAnimUtils.VIEW_ALPHA, 0f), navButtonsView, ) - val inShift: Float = navButtonsView.inShiftX + val inShift: Float = navButtonsView.context.inShiftX val inStartX = navBarTargetTranslationX + (if (isNavBarOnRight) -inShift else inShift) val fadeIn: Animator = createLocationInAnimator( diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java index 142f458b3b..4b977e0d23 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java @@ -510,6 +510,8 @@ public class TaskbarDragController extends DragController<BaseTaskbarContext> im } else { // This will take care of calling maybeOnDragEnd() after the animation animateGlobalDragViewToOriginalPosition(btv, dragEvent); + //TODO(b/399678274): hide drop target in shell + notifyBubbleBarItemDragCanceled(); } mActivity.getDragLayer().setOnDragListener(null); @@ -536,10 +538,10 @@ public class TaskbarDragController extends DragController<BaseTaskbarContext> im mControllers.taskbarAutohideSuspendController.updateFlag( TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_DRAGGING, false); mActivity.onDragEnd(); + // If an item is dropped on the bubble bar, the bubble bar handles the drop, + // so it should not collapse along with the taskbar. + boolean droppedOnBubbleBar = notifyBubbleBarItemDropped(); if (mReturnAnimator == null) { - // If an item is dropped on the bubble bar, the bubble bar handles the drop, - // so it should not collapse along with the taskbar. - boolean droppedOnBubbleBar = notifyBubbleBarItemDropped(); // Upon successful drag, immediately stash taskbar. // Note, this must be done last to ensure no AutohideSuspendFlags are active, as // that will prevent us from stashing until the timeout. @@ -563,12 +565,17 @@ public class TaskbarDragController extends DragController<BaseTaskbarContext> im BubbleBarViewController bubbleBarViewController = bc.bubbleBarViewController; boolean showingDropTarget = bubbleBarViewController.isShowingDropTarget(); if (showingDropTarget) { - bubbleBarViewController.onItemDroppedInBubbleBarDragZone(); + bubbleBarViewController.onItemDragCompleted(); } return showingDropTarget; }).orElse(false); } + private void notifyBubbleBarItemDragCanceled() { + mControllers.bubbleControllers.ifPresent(bc -> + bc.bubbleBarViewController.onItemDraggedOutsideBubbleBarDropZone()); + } + @Override protected void endDrag() { if (mDisallowGlobalDrag && !mIsDropHandledByDropTarget) { diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java index 1abef8a63f..6380c2371b 100644 --- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java +++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java @@ -18,6 +18,7 @@ package com.android.launcher3.taskbar.bubbles; import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA; import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; import android.animation.ValueAnimator; import android.annotation.NonNull; @@ -560,30 +561,52 @@ public class BubbleBarView extends FrameLayout { // First animator hides the bar. // After it completes, bubble positions in the bar and arrow position is updated. // Second animator is started to show the bar. - ObjectAnimator alphaOutAnim = ObjectAnimator.ofFloat( - this, getLocationAnimAlphaProperty(), 0f); - mBubbleBarLocationAnimator = BarsLocationAnimatorHelper.getBubbleBarLocationOutAnimator( - this, - bubbleBarLocation, - alphaOutAnim); + mBubbleBarLocationAnimator = animateToBubbleBarLocationOut(bubbleBarLocation); mBubbleBarLocationAnimator.addListener(AnimatorListeners.forEndCallback(() -> { - updateBubblesLayoutProperties(bubbleBarLocation); - mBubbleBarBackground.setAnchorLeft(bubbleBarLocation.isOnLeft(isLayoutRtl())); - ObjectAnimator alphaInAnim = ObjectAnimator.ofFloat(BubbleBarView.this, - getLocationAnimAlphaProperty(), 1f); - // Animate it in - mBubbleBarLocationAnimator = BarsLocationAnimatorHelper.getBubbleBarLocationInAnimator( - bubbleBarLocation, - mBubbleBarLocation, - getDistanceFromOtherSide(), - alphaInAnim, - BubbleBarView.this); + mBubbleBarLocationAnimator = animateToBubbleBarLocationIn(mBubbleBarLocation, + bubbleBarLocation); mBubbleBarLocationAnimator.start(); })); mBubbleBarLocationAnimator.start(); } + /** Creates animator for animating bubble bar in. */ + public Animator animateToBubbleBarLocationIn(BubbleBarLocation fromLocation, + BubbleBarLocation toLocation) { + updateBubblesLayoutProperties(toLocation); + mBubbleBarBackground.setAnchorLeft(toLocation.isOnLeft(isLayoutRtl())); + ObjectAnimator alphaInAnim = ObjectAnimator.ofFloat(BubbleBarView.this, + getLocationAnimAlphaProperty(), 1f); + return BarsLocationAnimatorHelper.getBubbleBarLocationInAnimator(toLocation, fromLocation, + getDistanceFromOtherSide(), alphaInAnim, this); + } + + /** + * Creates animator for animating bubble bar out. + * + * @param targetLocation the location bubble br should animate to. + */ + public Animator animateToBubbleBarLocationOut(BubbleBarLocation targetLocation) { + ObjectAnimator alphaOutAnim = ObjectAnimator.ofFloat( + this, getLocationAnimAlphaProperty(), 0f); + Animator outAnimation = BarsLocationAnimatorHelper.getBubbleBarLocationOutAnimator( + this, + targetLocation, + alphaOutAnim); + outAnimation.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(@NonNull Animator animation, boolean isReverse) { + // need to restore the original bar view state in case icon is dropped to the bubble + // bar original location + updateBubblesLayoutProperties(targetLocation); + mBubbleBarBackground.setAnchorLeft(targetLocation.isOnLeft(isLayoutRtl())); + setTranslationX(0f); + } + }); + return outAnimation; + } + /** * Get property that can be used to animate the alpha value for the bar. * When a bubble is being dragged, uses {@link #BUBBLE_DRAG_ALPHA}. diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java index 9fb283cccf..ce4a14f551 100644 --- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java +++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java @@ -194,9 +194,11 @@ public class BubbleBarViewController { private boolean mHiddenForStashed; private boolean mShouldShowEducation; public boolean mOverflowAdded; - private boolean mIsLocationUpdatedForDropTarget = false; private boolean mWasStashedBeforeEnteringBubbleDragZone = false; + /** This field is used solely to track the bubble bar location prior to the start of the drag */ + private @Nullable BubbleBarLocation mBubbleBarDragLocation; + private BubbleBarViewAnimator mBubbleBarViewAnimator; private final FrameLayout mBubbleBarContainer; private BubbleBarFlyoutController mBubbleBarFlyoutController; @@ -364,7 +366,7 @@ public class BubbleBarViewController { @Override public boolean isOnLeft() { boolean shouldRevertLocation = - mBarView.isShowingDropTarget() && mIsLocationUpdatedForDropTarget; + mBarView.isShowingDropTarget() && isLocationUpdatedForDropTarget(); boolean isOnLeft = mBarView.getBubbleBarLocation().isOnLeft(mBarView.isLayoutRtl()); return shouldRevertLocation != isOnLeft; } @@ -616,6 +618,17 @@ public class BubbleBarViewController { mBarView.animateToBubbleBarLocation(bubbleBarLocation); } + /** Return animator for animating bubble bar in. */ + public Animator animateBubbleBarLocationIn(BubbleBarLocation fromLocation, + BubbleBarLocation toLocation) { + return mBarView.animateToBubbleBarLocationIn(fromLocation, toLocation); + } + + /** Return animator for animating bubble bar out. */ + public Animator animateBubbleBarLocationOut(BubbleBarLocation toLocation) { + return mBarView.animateToBubbleBarLocationOut(toLocation); + } + /** Returns whether the Bubble Bar is currently displaying a drop target. */ public boolean isShowingDropTarget() { return mBarView.isShowingDropTarget(); @@ -628,25 +641,18 @@ public class BubbleBarViewController { * updated. */ public void onDragItemOverBubbleBarDragZone(@NonNull BubbleBarLocation bubbleBarLocation) { - Log.w("BBAnimation", "onDragItemOverBubbleBarDragZone()"); + mBubbleBarDragLocation = bubbleBarLocation; mBarView.showDropTarget(/* isDropTarget = */ true); - boolean isRtl = mBarView.isLayoutRtl(); - mIsLocationUpdatedForDropTarget = getBubbleBarLocation().isOnLeft(isRtl) - != bubbleBarLocation.isOnLeft(isRtl); mWasStashedBeforeEnteringBubbleDragZone = hasBubbles() && mBubbleStashController.isStashed(); if (mWasStashedBeforeEnteringBubbleDragZone) { - if (mIsLocationUpdatedForDropTarget) { - // bubble bar is stashed an location updated - //TODO(b/399678274) add animation - mBubbleStashController.showBubbleBarImmediate(); - animateBubbleBarLocation(bubbleBarLocation); - } else { - // bubble bar is stashed and location the same - just un-stash - mBubbleStashController.showBubbleBar(/* expandBubbles = */ false); - } + // bubble bar is stashed - un-stash at drag location + mBubbleStashController.showBubbleBarAtLocation( + /* fromLocation = */ getBubbleBarLocation(), + /* toLocation = */ mBubbleBarDragLocation + ); } else if (hasBubbles()) { - if (mIsLocationUpdatedForDropTarget) { + if (isLocationUpdatedForDropTarget()) { // bubble bar has bubbles and location is changed - animate bar to the opposite side animateBubbleBarLocation(bubbleBarLocation); } @@ -661,7 +667,12 @@ public class BubbleBarViewController { * {@link #onDragItemOverBubbleBarDragZone}}. */ public boolean isLocationUpdatedForDropTarget() { - return mIsLocationUpdatedForDropTarget; + if (mBubbleBarDragLocation == null) { + return false; + } + boolean isRtl = mBarView.isLayoutRtl(); + return getBubbleBarLocation().isOnLeft(isRtl) + != mBubbleBarDragLocation.isOnLeft(isRtl); } /** @@ -671,39 +682,34 @@ public class BubbleBarViewController { * mode and reset the value returned from {@link #isLocationUpdatedForDropTarget()} to false. */ public void onItemDraggedOutsideBubbleBarDropZone() { - Log.w("BBAnimation", "onItemDraggedOutsideBubbleBarDropZone()"); - mBarView.showDropTarget(/* isDropTarget = */ false); - if (mWasStashedBeforeEnteringBubbleDragZone) { - if (mIsLocationUpdatedForDropTarget) { - // bubble bar was stashed and location updated - //TODO(b/399678274) add animation - animateBubbleBarLocation(getBubbleBarLocation()); - mBubbleStashController.stashBubbleBarImmediate(); - } else { - // bubble bar was stashed and location the same - just stash it back - mBubbleStashController.stashBubbleBar(); - } + if (!isShowingDropTarget()) { + return; + } + if (mWasStashedBeforeEnteringBubbleDragZone && mBubbleBarDragLocation != null) { + // bubble bar was stashed - stash at original location + mBubbleStashController.stashBubbleBarToLocation( + /* fromLocation = */ mBubbleBarDragLocation, + /* toLocation = */ getBubbleBarLocation() + ); } else if (hasBubbles()) { - if (mIsLocationUpdatedForDropTarget) { - // bubble bar has bubbles and location was changed - return to the original location + if (isLocationUpdatedForDropTarget()) { + // bubble bar has bubbles and location was changed - return to the original + // location animateBubbleBarLocation(getBubbleBarLocation()); } } - mBubbleBarPinController.hideDropTarget(); - mIsLocationUpdatedForDropTarget = false; - mWasStashedBeforeEnteringBubbleDragZone = false; + onItemDragCompleted(); } /** * Notifies the controller that the drag has completed over the Bubble Bar drop zone. * The controller will hide the drop target if there are no bubbles and exit drop target mode. */ - public void onItemDroppedInBubbleBarDragZone() { - Log.w("BBAnimation", "onItemDroppedInBubbleBarDragZone()"); + public void onItemDragCompleted() { mBarView.showDropTarget(/* isDropTarget = */ false); mBubbleBarPinController.hideDropTarget(); - mIsLocationUpdatedForDropTarget = false; mWasStashedBeforeEnteringBubbleDragZone = false; + mBubbleBarDragLocation = null; } /** @@ -842,6 +848,7 @@ public class BubbleBarViewController { boolean hiddenForStashedAndNotAnimating = mHiddenForStashed && !mBubbleBarViewAnimator.isAnimating(); if (mHiddenForSysui || mHiddenForNoBubbles || hiddenForStashedAndNotAnimating) { + //TODO(b/404870188) this visibility change cause search view drag misbehavior mBarView.setVisibility(INVISIBLE); } else { mBarView.setVisibility(VISIBLE); diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashedHandleViewController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashedHandleViewController.java index 3640c3b60e..ec540e0088 100644 --- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashedHandleViewController.java +++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashedHandleViewController.java @@ -272,6 +272,11 @@ public class BubbleStashedHandleViewController { updateTranslationY(); } + /** Sets translation X for stash handle. */ + public void setTranslationX(float translationX) { + mStashedHandleView.setTranslationX(translationX); + } + private void updateTranslationY() { mStashedHandleView.setTranslationY(mTranslationForSwipeY + mTranslationForStashY); } diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/BubbleStashController.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/BubbleStashController.kt index fec1eaf55c..ec272ac873 100644 --- a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/BubbleStashController.kt +++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/BubbleStashController.kt @@ -131,6 +131,12 @@ interface BubbleStashController { */ fun stashBubbleBar() + /** + * Animates the bubble bar to the handle at provided location. Does not update bubble bar + * location. + */ + fun stashBubbleBarToLocation(fromLocation: BubbleBarLocation, toLocation: BubbleBarLocation) {} + /** Shows the bubble bar, and expands bubbles depending on [expandBubbles]. */ fun showBubbleBar(expandBubbles: Boolean) { showBubbleBar(expandBubbles = expandBubbles, bubbleBarGesture = false) @@ -144,6 +150,9 @@ interface BubbleStashController { */ fun showBubbleBar(expandBubbles: Boolean, bubbleBarGesture: Boolean) + /** Animates the bubble bar at the provided location. Does not update bubble bar location. */ + fun showBubbleBarAtLocation(fromLocation: BubbleBarLocation, toLocation: BubbleBarLocation) {} + // TODO(b/354218264): Move to BubbleBarViewAnimator /** * The difference on the Y axis between the center of the handle and the center of the bubble diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashController.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashController.kt index 9c148e2191..82bb071bc3 100644 --- a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashController.kt +++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashController.kt @@ -18,6 +18,7 @@ package com.android.launcher3.taskbar.bubbles.stashing import android.animation.Animator import android.animation.AnimatorSet +import android.animation.ValueAnimator import android.content.Context import android.graphics.Rect import android.view.MotionEvent @@ -31,6 +32,12 @@ import com.android.app.animation.Interpolators.LINEAR import com.android.launcher3.R import com.android.launcher3.anim.AnimatedFloat import com.android.launcher3.anim.SpringAnimationBuilder +import com.android.launcher3.taskbar.BarsLocationAnimatorHelper.FADE_IN_ANIM_ALPHA_DURATION_MS +import com.android.launcher3.taskbar.BarsLocationAnimatorHelper.FADE_OUT_ANIM_ALPHA_DELAY_MS +import com.android.launcher3.taskbar.BarsLocationAnimatorHelper.FADE_OUT_ANIM_ALPHA_DURATION_MS +import com.android.launcher3.taskbar.BarsLocationAnimatorHelper.FADE_OUT_ANIM_POSITION_DURATION_MS +import com.android.launcher3.taskbar.BarsLocationAnimatorHelper.inShiftX +import com.android.launcher3.taskbar.BarsLocationAnimatorHelper.outShift import com.android.launcher3.taskbar.TaskbarInsetsController import com.android.launcher3.taskbar.TaskbarStashController.TASKBAR_STASH_ALPHA_START_DELAY import com.android.launcher3.taskbar.TaskbarStashController.TRANSIENT_TASKBAR_STASH_ALPHA_DURATION @@ -44,6 +51,7 @@ import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController.Task import com.android.launcher3.util.MultiPropertyFactory import com.android.wm.shell.shared.animation.PhysicsAnimator import com.android.wm.shell.shared.bubbles.BubbleBarLocation +import com.android.wm.shell.shared.bubbles.ContextUtils.isRtl import kotlin.math.max class TransientBubbleStashController( @@ -187,6 +195,11 @@ class TransientBubbleStashController( } override fun showBubbleBarImmediate(bubbleBarTranslationY: Float) { + showBubbleBarImmediateVisually(bubbleBarTranslationY) + onIsStashedChanged() + } + + private fun showBubbleBarImmediateVisually(bubbleBarTranslationY: Float) { bubbleStashedHandleViewController?.setTranslationYForSwipe(0f) stashHandleViewAlpha?.value = 0f this.bubbleBarTranslationYAnimator.updateValue(bubbleBarTranslationY) @@ -197,10 +210,14 @@ class TransientBubbleStashController( bubbleBarBackgroundScaleY.updateValue(1f) isStashed = false bubbleBarViewController.setHiddenForStashed(false) - onIsStashedChanged() } override fun stashBubbleBarImmediate() { + stashBubbleBarImmediateVisually() + onIsStashedChanged() + } + + private fun stashBubbleBarImmediateVisually() { bubbleStashedHandleViewController?.setTranslationYForSwipe(0f) stashHandleViewAlpha?.value = 1f this.bubbleBarTranslationYAnimator.updateValue(getStashTranslation()) @@ -212,7 +229,6 @@ class TransientBubbleStashController( bubbleBarBackgroundScaleY.updateValue(getStashScaleY()) isStashed = true bubbleBarViewController.setHiddenForStashed(true) - onIsStashedChanged() } override fun getTouchableHeight(): Int = @@ -247,6 +263,29 @@ class TransientBubbleStashController( updateStashedAndExpandedState(stash = true, expand = false) } + override fun stashBubbleBarToLocation( + fromLocation: BubbleBarLocation, + toLocation: BubbleBarLocation, + ) { + if (fromLocation.isSameSideWith(toLocation)) { + updateStashedAndExpandedState( + stash = true, + expand = false, + updateTouchRegionOnEnd = false, + ) + return + } + cancelAnimation() + animator = + AnimatorSet().apply { + playSequentially( + bubbleBarViewController.animateBubbleBarLocationOut(toLocation), + createHandleInAnimator(location = toLocation), + ) + start() + } + } + override fun showBubbleBar(expandBubbles: Boolean, bubbleBarGesture: Boolean) { updateStashedAndExpandedState( stash = false, @@ -255,6 +294,33 @@ class TransientBubbleStashController( ) } + override fun showBubbleBarAtLocation( + fromLocation: BubbleBarLocation, + toLocation: BubbleBarLocation, + ) { + if (fromLocation.isSameSideWith(toLocation)) { + updateStashedAndExpandedState( + stash = false, + expand = false, + updateTouchRegionOnEnd = false, + ) + return + } + cancelAnimation() + val bubbleBarInAnimation = + bubbleBarViewController.animateBubbleBarLocationIn(fromLocation, toLocation).apply { + doOnStart { showBubbleBarImmediateVisually(bubbleBarTranslationY) } + } + animator = + AnimatorSet().apply { + playSequentially( + createHandleOutAnimator(location = toLocation), + bubbleBarInAnimation, + ) + start() + } + } + override fun getDiffBetweenHandleAndBarCenters(): Float { // the difference between the centers of the handle and the bubble bar is the difference // between their distance from the bottom of the screen. @@ -392,7 +458,7 @@ class TransientBubbleStashController( bubbleBarAlpha.value = 1f } animatorSet.doOnEnd { - animator = null + cancelAnimation() controllersAfterInitAction.runAfterInit { if (isStashed) { bubbleBarAlpha.value = 0f @@ -486,6 +552,7 @@ class TransientBubbleStashController( stash: Boolean, expand: Boolean, bubbleBarGesture: Boolean = false, + updateTouchRegionOnEnd: Boolean = true, ) { if (bubbleBarViewController.isHiddenForNoBubbles) { // If there are no bubbles the bar and handle are invisible, nothing to do here. @@ -498,11 +565,13 @@ class TransientBubbleStashController( // notify the view controller that the stash state is about to change so that it can // cancel an ongoing animation if there is one. bubbleBarViewController.onStashStateChanging() - animator?.cancel() + cancelAnimation() animator = createStashAnimator(isStashed, BAR_STASH_DURATION).apply { updateBarVisibility(isStashed) - updateTouchRegionOnAnimationEnd() + if (updateTouchRegionOnEnd) { + updateTouchRegionOnAnimationEnd() + } start() } } @@ -512,6 +581,11 @@ class TransientBubbleStashController( } } + private fun cancelAnimation() { + animator?.cancel() + animator = null + } + override fun getHandleViewAlpha(): MultiPropertyFactory<View>.MultiProperty? = // only return handle alpha if the bubble bar is stashed and has bubbles if (isStashed && bubbleBarViewController.hasBubbles()) { @@ -534,6 +608,49 @@ class TransientBubbleStashController( return this } + // TODO(b/399678274) add tests + private fun createHandleInAnimator(location: BubbleBarLocation): Animator? { + val stashHandleViewController = bubbleStashedHandleViewController ?: return null + val handleAlpha = stashHandleViewController.stashedHandleAlpha.get(0) + val shift = context.inShiftX + val startX = if (location.isOnLeft(context.isRtl)) shift else -shift + val handleTranslationX = + ValueAnimator.ofFloat(startX, 0f).apply { + addUpdateListener { v -> + stashHandleViewController.setTranslationX(v.animatedValue as Float) + } + duration = FADE_IN_ANIM_ALPHA_DURATION_MS + } + val handleAlphaAnimation = + handleAlpha.animateToValue(1f).apply { duration = FADE_IN_ANIM_ALPHA_DURATION_MS } + return AnimatorSet().apply { + playTogether(handleTranslationX, handleAlphaAnimation) + doOnStart { stashBubbleBarImmediateVisually() } + } + } + + private fun createHandleOutAnimator(location: BubbleBarLocation): Animator? { + val stashHandleViewController = bubbleStashedHandleViewController ?: return null + val handleAlpha = stashHandleViewController.stashedHandleAlpha.get(0) + val shift = context.outShift + val endX = if (location.isOnLeft(context.isRtl)) -shift else shift + val handleTranslationX = + ValueAnimator.ofFloat(0f, endX).apply { + addUpdateListener { v -> + stashHandleViewController.setTranslationX(v.animatedValue as Float) + } + duration = FADE_OUT_ANIM_POSITION_DURATION_MS + // in case item dropped to the opposite side - need to clear translation + doOnEnd { stashHandleViewController.setTranslationX(0f) } + } + val handleAlphaAnimation = + handleAlpha.animateToValue(0f).apply { + duration = FADE_OUT_ANIM_ALPHA_DURATION_MS + startDelay = FADE_OUT_ANIM_ALPHA_DELAY_MS + } + return AnimatorSet().apply { playTogether(handleTranslationX, handleAlphaAnimation) } + } + private fun Animator.setBubbleBarPivotDuringAnim(pivotX: Float, pivotY: Float): Animator { var initialPivotX = Float.NaN var initialPivotY = Float.NaN @@ -549,4 +666,9 @@ class TransientBubbleStashController( } return this } + + private fun BubbleBarLocation.isSameSideWith(anotherLocation: BubbleBarLocation): Boolean { + val isRtl = context.isRtl + return this.isOnLeft(isRtl) == anotherLocation.isOnLeft(isRtl) + } } |