Loading quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt +10 −0 Original line number Diff line number Diff line Loading @@ -153,6 +153,16 @@ class TaskbarInsetsController(val context: TaskbarActivityContext) : LoggableTas context.deviceProfile.widthPx, windowLayoutParams.height ) // if there's an animating bubble add it to the touch region so that it's clickable val animatingBubbleBounds = controllers.bubbleControllers .getOrNull() ?.bubbleBarViewController ?.animatingBubbleBounds if (animatingBubbleBounds != null) { defaultTouchableRegion.op(animatingBubbleBounds, Region.Op.UNION) } } // Pre-calculate insets for different providers across different rotations for this gravity Loading quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java +32 −1 Original line number Diff line number Diff line Loading @@ -104,6 +104,8 @@ public class BubbleBarView extends FrameLayout { * updates the bounds and accounts for translation. */ private final Rect mBubbleBarBounds = new Rect(); /** The bounds of the animating bubble in the coordinate space of the BubbleBarView. */ private final Rect mAnimatingBubbleBounds = new Rect(); // The amount the bubbles overlap when they are stacked in the bubble bar private final float mIconOverlapAmount; // The spacing between the bubbles when bubble bar is expanded Loading Loading @@ -460,6 +462,30 @@ public class BubbleBarView extends FrameLayout { return mBubbleBarBounds; } /** Returns the bounds of the animating bubble, or {@code null} if no bubble is animating. */ @Nullable public Rect getAnimatingBubbleBounds() { if (mIsAnimatingNewBubble) { return mAnimatingBubbleBounds; } return null; } /** * Updates the animating bubble bounds. This should be called when the bubble is fully animated * in so that we can include it in taskbar touchable region. * * <p>The bounds are adjusted to the coordinate space of BubbleBarView so that it can be used * by taskbar. */ public void updateAnimatingBubbleBounds(int left, int top, int width, int height) { Rect bubbleBarBounds = getBubbleBarBounds(); mAnimatingBubbleBounds.left = bubbleBarBounds.left + left; mAnimatingBubbleBounds.top = bubbleBarBounds.top + top; mAnimatingBubbleBounds.right = mAnimatingBubbleBounds.left + width; mAnimatingBubbleBounds.bottom = mAnimatingBubbleBounds.top + height; } /** * Set bubble bar relative pivot value for X and Y, applied as a fraction of view width/height * respectively. If the value is not in range of 0 to 1 it will be normalized. Loading Loading @@ -852,10 +878,15 @@ public class BubbleBarView extends FrameLayout { @Override public boolean onInterceptTouchEvent(MotionEvent ev) { if (!mIsBarExpanded) { if (!mIsBarExpanded && !mIsAnimatingNewBubble) { // When the bar is collapsed, all taps on it should expand it. return true; } return super.onInterceptTouchEvent(ev); } /** Whether a new bubble is currently animating. */ public boolean isAnimatingNewBubble() { return mIsAnimatingNewBubble; } } quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java +15 −0 Original line number Diff line number Diff line Loading @@ -138,6 +138,15 @@ public class BubbleBarViewController { if (bubble == null) { Log.e(TAG, "bubble click listener, bubble was null"); } if (mBarView.isAnimatingNewBubble()) { mBubbleBarViewAnimator.onBubbleClickedWhileAnimating(); mBubbleStashController.showBubbleBarImmediate(); setExpanded(true); mBubbleBarController.showAndSelectBubble(bubble); return; } final String currentlySelected = mBubbleBarController.getSelectedBubbleKey(); if (mBarView.isExpanded() && Objects.equals(bubble.getKey(), currentlySelected)) { // Tapping the currently selected bubble while expanded collapses the view. Loading Loading @@ -213,6 +222,12 @@ public class BubbleBarViewController { return mBarView.getBubbleBarBounds(); } /** The bounds of the animating bubble, or {@code null} if no bubble is animating. */ @Nullable public Rect getAnimatingBubbleBounds() { return mBarView.getAnimatingBubbleBounds(); } /** The horizontal margin of the bubble bar from the edge of the screen. */ public int getHorizontalMargin() { return mBarView.getHorizontalMargin(); Loading quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashController.java +16 −1 Original line number Diff line number Diff line Loading @@ -347,7 +347,7 @@ public class BubbleStashController { hotseatCellHeight - mUnstashedHeight) / 2; } float getBubbleBarTranslationY() { public float getBubbleBarTranslationY() { // If we're on home, adjust the translation so the bubble bar aligns with hotseat. // Otherwise we're either showing in an app or in overview. In either case adjust it so // the bubble bar aligns with the taskbar. Loading @@ -374,4 +374,19 @@ public class BubbleStashController { public PhysicsAnimator<View> getStashedHandlePhysicsAnimator() { return mHandleViewController.getPhysicsAnimator(); } /** Notifies taskbar that it should update its touchable region. */ public void updateTaskbarTouchRegion() { mTaskbarInsetsController.onTaskbarOrBubblebarWindowHeightOrInsetsChanged(); } /** Shows the bubble bar immediately without animation. */ public void showBubbleBarImmediate() { mHandleViewController.setTranslationYForSwipe(0); mIconTranslationYForStash.updateValue(getBubbleBarTranslationY()); mIconAlphaForStash.setValue(1); mIconScaleForStash.updateValue(1); mIsStashed = false; onIsStashedChanged(); } } quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt +44 −7 Original line number Diff line number Diff line Loading @@ -35,6 +35,8 @@ constructor( private val scheduler: Scheduler = HandlerScheduler(bubbleBarView) ) { private var animatingBubble: AnimatingBubble? = null private companion object { /** The time to show the flyout. */ const val FLYOUT_DELAY_MS: Long = 2500 Loading @@ -54,26 +56,40 @@ constructor( const val BUBBLE_ANIMATION_STASH_HANDLE_TRANSLATION_Y = -20f } /** Wrapper around the animating bubble with its show and hide animations. */ private data class AnimatingBubble( val bubbleView: BubbleView, val showAnimation: Runnable, val hideAnimation: Runnable ) /** An interface for scheduling jobs. */ interface Scheduler { /** Schedule the given [block] to run. */ fun post(block: () -> Unit) fun post(block: Runnable) /** Schedule the given [block] to start with a delay of [delayMillis]. */ fun postDelayed(delayMillis: Long, block: () -> Unit) fun postDelayed(delayMillis: Long, block: Runnable) /** Cancel the given [block] if it hasn't started yet. */ fun cancel(block: Runnable) } /** A [Scheduler] that uses a Handler to run jobs. */ private class HandlerScheduler(private val view: View) : Scheduler { override fun post(block: () -> Unit) { override fun post(block: Runnable) { view.post(block) } override fun postDelayed(delayMillis: Long, block: () -> Unit) { override fun postDelayed(delayMillis: Long, block: Runnable) { view.postDelayed(block, delayMillis) } override fun cancel(block: Runnable) { view.removeCallbacks(block) } } private val springConfig = Loading @@ -91,6 +107,7 @@ constructor( // and the second part hides it after a delay. val showAnimation = buildShowAnimation(bubbleView, b.key) val hideAnimation = buildHideAnimation(bubbleView) animatingBubble = AnimatingBubble(bubbleView, showAnimation, hideAnimation) scheduler.post(showAnimation) scheduler.postDelayed(FLYOUT_DELAY_MS, hideAnimation) } Loading @@ -113,7 +130,7 @@ constructor( private fun buildShowAnimation( bubbleView: BubbleView, key: String, ): () -> Unit = { ) = Runnable { bubbleBarView.prepareForAnimatingBubbleWhileStashed(key) // calculate the initial translation x the bubble should have in order to align it with the // stash handle. Loading @@ -140,7 +157,7 @@ constructor( // map the path [0, BUBBLE_ANIMATION_STASH_HANDLE_TRANSLATION_Y] to [0,1] val fraction = ty / BUBBLE_ANIMATION_STASH_HANDLE_TRANSLATION_Y target.alpha = 1 - fraction / 2 target.alpha = 1 - fraction } ty >= totalTranslationY -> { // this is the second leg of the animation. the handle should be completely Loading Loading @@ -173,6 +190,16 @@ constructor( } } } animator.addEndListener { _, _, _, _, _, _, _ -> // the bubble is now fully settled in. make it touchable bubbleBarView.updateAnimatingBubbleBounds( bubbleView.left, bubbleView.top, bubbleView.width, bubbleView.height ) bubbleStashController.updateTaskbarTouchRegion() } animator.start() } Loading @@ -189,7 +216,7 @@ constructor( * 1. In the second part the bubble is fully hidden and the handle animates in. * 1. The third part is the overshoot. The handle is made fully visible. */ private fun buildHideAnimation(bubbleView: BubbleView): () -> Unit = { private fun buildHideAnimation(bubbleView: BubbleView) = Runnable { // this is the total distance that both the stashed handle and the bubble will be traveling val totalTranslationY = BUBBLE_ANIMATION_BUBBLE_TRANSLATION_Y + BUBBLE_ANIMATION_STASH_HANDLE_TRANSLATION_Y Loading Loading @@ -230,6 +257,7 @@ constructor( } } animator.addEndListener { _, _, _, _, _, _, _ -> animatingBubble = null bubbleView.alpha = 0f bubbleView.translationY = 0f bubbleView.scaleY = 1f Loading @@ -237,9 +265,18 @@ constructor( bubbleBarView.alpha = 0f } bubbleBarView.onAnimatingBubbleCompleted() bubbleStashController.updateTaskbarTouchRegion() } animator.start() } /** Handles clicking on the animating bubble while the animation is still playing. */ fun onBubbleClickedWhileAnimating() { val hideAnimation = animatingBubble?.hideAnimation ?: return scheduler.cancel(hideAnimation) bubbleBarView.onAnimatingBubbleCompleted() animatingBubble = null } } /** The X position in screen coordinates of the center of the bubble. */ Loading Loading
quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt +10 −0 Original line number Diff line number Diff line Loading @@ -153,6 +153,16 @@ class TaskbarInsetsController(val context: TaskbarActivityContext) : LoggableTas context.deviceProfile.widthPx, windowLayoutParams.height ) // if there's an animating bubble add it to the touch region so that it's clickable val animatingBubbleBounds = controllers.bubbleControllers .getOrNull() ?.bubbleBarViewController ?.animatingBubbleBounds if (animatingBubbleBounds != null) { defaultTouchableRegion.op(animatingBubbleBounds, Region.Op.UNION) } } // Pre-calculate insets for different providers across different rotations for this gravity Loading
quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java +32 −1 Original line number Diff line number Diff line Loading @@ -104,6 +104,8 @@ public class BubbleBarView extends FrameLayout { * updates the bounds and accounts for translation. */ private final Rect mBubbleBarBounds = new Rect(); /** The bounds of the animating bubble in the coordinate space of the BubbleBarView. */ private final Rect mAnimatingBubbleBounds = new Rect(); // The amount the bubbles overlap when they are stacked in the bubble bar private final float mIconOverlapAmount; // The spacing between the bubbles when bubble bar is expanded Loading Loading @@ -460,6 +462,30 @@ public class BubbleBarView extends FrameLayout { return mBubbleBarBounds; } /** Returns the bounds of the animating bubble, or {@code null} if no bubble is animating. */ @Nullable public Rect getAnimatingBubbleBounds() { if (mIsAnimatingNewBubble) { return mAnimatingBubbleBounds; } return null; } /** * Updates the animating bubble bounds. This should be called when the bubble is fully animated * in so that we can include it in taskbar touchable region. * * <p>The bounds are adjusted to the coordinate space of BubbleBarView so that it can be used * by taskbar. */ public void updateAnimatingBubbleBounds(int left, int top, int width, int height) { Rect bubbleBarBounds = getBubbleBarBounds(); mAnimatingBubbleBounds.left = bubbleBarBounds.left + left; mAnimatingBubbleBounds.top = bubbleBarBounds.top + top; mAnimatingBubbleBounds.right = mAnimatingBubbleBounds.left + width; mAnimatingBubbleBounds.bottom = mAnimatingBubbleBounds.top + height; } /** * Set bubble bar relative pivot value for X and Y, applied as a fraction of view width/height * respectively. If the value is not in range of 0 to 1 it will be normalized. Loading Loading @@ -852,10 +878,15 @@ public class BubbleBarView extends FrameLayout { @Override public boolean onInterceptTouchEvent(MotionEvent ev) { if (!mIsBarExpanded) { if (!mIsBarExpanded && !mIsAnimatingNewBubble) { // When the bar is collapsed, all taps on it should expand it. return true; } return super.onInterceptTouchEvent(ev); } /** Whether a new bubble is currently animating. */ public boolean isAnimatingNewBubble() { return mIsAnimatingNewBubble; } }
quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java +15 −0 Original line number Diff line number Diff line Loading @@ -138,6 +138,15 @@ public class BubbleBarViewController { if (bubble == null) { Log.e(TAG, "bubble click listener, bubble was null"); } if (mBarView.isAnimatingNewBubble()) { mBubbleBarViewAnimator.onBubbleClickedWhileAnimating(); mBubbleStashController.showBubbleBarImmediate(); setExpanded(true); mBubbleBarController.showAndSelectBubble(bubble); return; } final String currentlySelected = mBubbleBarController.getSelectedBubbleKey(); if (mBarView.isExpanded() && Objects.equals(bubble.getKey(), currentlySelected)) { // Tapping the currently selected bubble while expanded collapses the view. Loading Loading @@ -213,6 +222,12 @@ public class BubbleBarViewController { return mBarView.getBubbleBarBounds(); } /** The bounds of the animating bubble, or {@code null} if no bubble is animating. */ @Nullable public Rect getAnimatingBubbleBounds() { return mBarView.getAnimatingBubbleBounds(); } /** The horizontal margin of the bubble bar from the edge of the screen. */ public int getHorizontalMargin() { return mBarView.getHorizontalMargin(); Loading
quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashController.java +16 −1 Original line number Diff line number Diff line Loading @@ -347,7 +347,7 @@ public class BubbleStashController { hotseatCellHeight - mUnstashedHeight) / 2; } float getBubbleBarTranslationY() { public float getBubbleBarTranslationY() { // If we're on home, adjust the translation so the bubble bar aligns with hotseat. // Otherwise we're either showing in an app or in overview. In either case adjust it so // the bubble bar aligns with the taskbar. Loading @@ -374,4 +374,19 @@ public class BubbleStashController { public PhysicsAnimator<View> getStashedHandlePhysicsAnimator() { return mHandleViewController.getPhysicsAnimator(); } /** Notifies taskbar that it should update its touchable region. */ public void updateTaskbarTouchRegion() { mTaskbarInsetsController.onTaskbarOrBubblebarWindowHeightOrInsetsChanged(); } /** Shows the bubble bar immediately without animation. */ public void showBubbleBarImmediate() { mHandleViewController.setTranslationYForSwipe(0); mIconTranslationYForStash.updateValue(getBubbleBarTranslationY()); mIconAlphaForStash.setValue(1); mIconScaleForStash.updateValue(1); mIsStashed = false; onIsStashedChanged(); } }
quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt +44 −7 Original line number Diff line number Diff line Loading @@ -35,6 +35,8 @@ constructor( private val scheduler: Scheduler = HandlerScheduler(bubbleBarView) ) { private var animatingBubble: AnimatingBubble? = null private companion object { /** The time to show the flyout. */ const val FLYOUT_DELAY_MS: Long = 2500 Loading @@ -54,26 +56,40 @@ constructor( const val BUBBLE_ANIMATION_STASH_HANDLE_TRANSLATION_Y = -20f } /** Wrapper around the animating bubble with its show and hide animations. */ private data class AnimatingBubble( val bubbleView: BubbleView, val showAnimation: Runnable, val hideAnimation: Runnable ) /** An interface for scheduling jobs. */ interface Scheduler { /** Schedule the given [block] to run. */ fun post(block: () -> Unit) fun post(block: Runnable) /** Schedule the given [block] to start with a delay of [delayMillis]. */ fun postDelayed(delayMillis: Long, block: () -> Unit) fun postDelayed(delayMillis: Long, block: Runnable) /** Cancel the given [block] if it hasn't started yet. */ fun cancel(block: Runnable) } /** A [Scheduler] that uses a Handler to run jobs. */ private class HandlerScheduler(private val view: View) : Scheduler { override fun post(block: () -> Unit) { override fun post(block: Runnable) { view.post(block) } override fun postDelayed(delayMillis: Long, block: () -> Unit) { override fun postDelayed(delayMillis: Long, block: Runnable) { view.postDelayed(block, delayMillis) } override fun cancel(block: Runnable) { view.removeCallbacks(block) } } private val springConfig = Loading @@ -91,6 +107,7 @@ constructor( // and the second part hides it after a delay. val showAnimation = buildShowAnimation(bubbleView, b.key) val hideAnimation = buildHideAnimation(bubbleView) animatingBubble = AnimatingBubble(bubbleView, showAnimation, hideAnimation) scheduler.post(showAnimation) scheduler.postDelayed(FLYOUT_DELAY_MS, hideAnimation) } Loading @@ -113,7 +130,7 @@ constructor( private fun buildShowAnimation( bubbleView: BubbleView, key: String, ): () -> Unit = { ) = Runnable { bubbleBarView.prepareForAnimatingBubbleWhileStashed(key) // calculate the initial translation x the bubble should have in order to align it with the // stash handle. Loading @@ -140,7 +157,7 @@ constructor( // map the path [0, BUBBLE_ANIMATION_STASH_HANDLE_TRANSLATION_Y] to [0,1] val fraction = ty / BUBBLE_ANIMATION_STASH_HANDLE_TRANSLATION_Y target.alpha = 1 - fraction / 2 target.alpha = 1 - fraction } ty >= totalTranslationY -> { // this is the second leg of the animation. the handle should be completely Loading Loading @@ -173,6 +190,16 @@ constructor( } } } animator.addEndListener { _, _, _, _, _, _, _ -> // the bubble is now fully settled in. make it touchable bubbleBarView.updateAnimatingBubbleBounds( bubbleView.left, bubbleView.top, bubbleView.width, bubbleView.height ) bubbleStashController.updateTaskbarTouchRegion() } animator.start() } Loading @@ -189,7 +216,7 @@ constructor( * 1. In the second part the bubble is fully hidden and the handle animates in. * 1. The third part is the overshoot. The handle is made fully visible. */ private fun buildHideAnimation(bubbleView: BubbleView): () -> Unit = { private fun buildHideAnimation(bubbleView: BubbleView) = Runnable { // this is the total distance that both the stashed handle and the bubble will be traveling val totalTranslationY = BUBBLE_ANIMATION_BUBBLE_TRANSLATION_Y + BUBBLE_ANIMATION_STASH_HANDLE_TRANSLATION_Y Loading Loading @@ -230,6 +257,7 @@ constructor( } } animator.addEndListener { _, _, _, _, _, _, _ -> animatingBubble = null bubbleView.alpha = 0f bubbleView.translationY = 0f bubbleView.scaleY = 1f Loading @@ -237,9 +265,18 @@ constructor( bubbleBarView.alpha = 0f } bubbleBarView.onAnimatingBubbleCompleted() bubbleStashController.updateTaskbarTouchRegion() } animator.start() } /** Handles clicking on the animating bubble while the animation is still playing. */ fun onBubbleClickedWhileAnimating() { val hideAnimation = animatingBubble?.hideAnimation ?: return scheduler.cancel(hideAnimation) bubbleBarView.onAnimatingBubbleCompleted() animatingBubble = null } } /** The X position in screen coordinates of the center of the bubble. */ Loading