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

Commit 126be562 authored by Mykola Podolian's avatar Mykola Podolian Committed by Android (Google) Code Review
Browse files

Merge "Added BubbleStashController interface" into main

parents c1d3fa45 08e98a2c
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -250,7 +250,7 @@ public class BubbleBarViewController {
        return mBubbleBarTranslationY;
    }

    float getBubbleBarCollapsedHeight() {
    public float getBubbleBarCollapsedHeight() {
        return mBarView.getBubbleBarCollapsedHeight();
    }

+202 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.launcher3.taskbar.bubbles.stashing

import android.view.InsetsController
import android.view.MotionEvent
import android.view.View
import com.android.launcher3.taskbar.TaskbarInsetsController
import com.android.launcher3.taskbar.bubbles.BubbleBarView
import com.android.launcher3.taskbar.bubbles.BubbleBarViewController
import com.android.launcher3.taskbar.bubbles.BubbleStashedHandleViewController
import com.android.wm.shell.common.bubbles.BubbleBarLocation
import com.android.wm.shell.shared.animation.PhysicsAnimator
import java.io.PrintWriter

/** StashController that defines stashing behaviour for the taskbar modes. */
interface BubbleStashController {

    /**
     * Abstraction on the task bar activity context to only provide the dimensions required for
     * [BubbleBarView] translation Y computation.
     */
    interface TaskbarHotseatDimensionsProvider {

        /** Provides taskbar bottom space in pixels. */
        fun getTaskbarBottomSpace(): Int

        /** Provides taskbar height in pixels. */
        fun getTaskbarHeight(): Int

        /** Provides hotseat bottom space in pixels. */
        fun getHotseatBottomSpace(): Int

        /** Provides hotseat height in pixels. */
        fun getHotseatHeight(): Int
    }

    /** Execute passed action only after controllers are initiated. */
    interface ControllersAfterInitAction {
        /** Execute action after controllers are initiated. */
        fun runAfterInit(action: () -> Unit)
    }

    /** Whether bubble bar is currently stashed */
    val isStashed: Boolean

    /** Whether launcher enters or exits the home page. */
    var isBubblesShowingOnHome: Boolean

    /** Whether launcher enters or exits the overview page. */
    var isBubblesShowingOnOverview: Boolean

    /** Updated when sysui locked state changes, when locked, bubble bar is not shown. */
    var isSysuiLocked: Boolean

    /** Whether there is a transient taskbar mode */
    val isTransientTaskBar: Boolean

    /** Whether stash control has a handle view */
    val hasHandleView: Boolean

    /** Initialize controller */
    fun init(
        taskbarInsetsController: TaskbarInsetsController,
        bubbleBarViewController: BubbleBarViewController,
        bubbleStashedHandleViewController: BubbleStashedHandleViewController?,
        controllersAfterInitAction: ControllersAfterInitAction
    )

    /** Sets stashed and expanded state of the bubble bar */
    fun updateStashedAndExpandedState(stash: Boolean = false, expand: Boolean = false)

    /**
     * Shows the bubble bar at [getBubbleBarTranslationY] position immediately without animation.
     */
    fun showBubbleBarImmediate()

    /** Shows the bubble bar at [bubbleBarTranslationY] position immediately without animation. */
    fun showBubbleBarImmediate(bubbleBarTranslationY: Float)

    /** Stashes the bubble bar immediately without animation. */
    fun stashBubbleBarImmediate()

    /** Returns the touchable height of the bubble bar based on it's stashed state. */
    fun getTouchableHeight(): Int

    /** Whether bubble bar is currently visible */
    fun isBubbleBarVisible(): Boolean

    /**
     * Updates the values of the internal animators after the new bubble animation was interrupted
     *
     * @param isStashed whether the current state should be stashed
     * @param bubbleBarTranslationY the current bubble bar translation. this is only used if the
     *   bubble bar is showing to ensure that the stash animator runs smoothly.
     */
    fun onNewBubbleAnimationInterrupted(isStashed: Boolean, bubbleBarTranslationY: Float)

    /** Checks whether the motion event is over the stash handle or bubble bar. */
    fun isEventOverBubbleBarViews(ev: MotionEvent): Boolean

    /** Set a bubble bar location */
    fun setBubbleBarLocation(bubbleBarLocation: BubbleBarLocation)

    /**
     * Stashes the bubble bar (transform to the handle view), or just shrink width of the expanded
     * bubble bar based on the controller implementation.
     */
    fun stashBubbleBar() {
        updateStashedAndExpandedState(stash = true, expand = false)
    }

    /** Shows the bubble bar, and expands bubbles depending on [expandBubbles]. */
    fun showBubbleBar(expandBubbles: Boolean) {
        updateStashedAndExpandedState(stash = false, expandBubbles)
    }

    // TODO(b/354218264): Move to BubbleBarViewAnimator
    /**
     * The difference on the Y axis between the center of the handle and the center of the bubble
     * bar.
     */
    fun getSlideInAnimationDistanceY(): Float

    // TODO(b/354218264): Move to BubbleBarViewAnimator
    /** The distance the handle moves as part of the new bubble animation. */
    fun getStashedHandleTranslationForNewBubbleAnimation(): Float

    // TODO(b/354218264): Move to BubbleBarViewAnimator
    /** Returns the [PhysicsAnimator] for the stashed handle view. */
    fun getStashedHandlePhysicsAnimator(): PhysicsAnimator<View>?

    // TODO(b/354218264): Move to BubbleBarViewAnimator
    /** Notifies taskbar that it should update its touchable region. */
    fun updateTaskbarTouchRegion()

    // TODO(b/354218264): Move to BubbleBarViewAnimator
    /** Set the translation Y for the stashed handle. */
    fun setHandleTranslationY(translationY: Float)

    /**
     * Returns bubble bar Y position according to [isBubblesShowingOnHome] and
     * [isBubblesShowingOnOverview] values. Default implementation only analyse
     * [isBubblesShowingOnHome] and return translationY to align with the hotseat vertical center.
     * For Other cases align bubbles with the taskbar.
     */
    val bubbleBarTranslationY: Float
        get() =
            if (isBubblesShowingOnHome) {
                bubbleBarTranslationYForHotseat
            } else {
                bubbleBarTranslationYForTaskbar
            }

    /** Translation Y to align the bubble bar with the hotseat. */
    val bubbleBarTranslationYForTaskbar: Float

    /** Return translation Y to align the bubble bar with the taskbar. */
    val bubbleBarTranslationYForHotseat: Float

    /** Dumps the state of BubbleStashController. */
    fun dump(pw: PrintWriter) {
        pw.println("Bubble stash controller state:")
        pw.println("  isStashed: $isStashed")
        pw.println("  isBubblesShowingOnOverview: $isBubblesShowingOnOverview")
        pw.println("  isBubblesShowingOnHome: $isBubblesShowingOnHome")
        pw.println("  isSysuiLocked: $isSysuiLocked")
    }

    companion object {
        /** How long to stash/unstash. */
        const val BAR_STASH_DURATION = InsetsController.ANIMATION_DURATION_RESIZE.toLong()

        /** How long to translate Y coordinate of the BubbleBar. */
        const val BAR_TRANSLATION_DURATION = 300L

        /** The scale bubble bar animates to when being stashed. */
        const val STASHED_BAR_SCALE = 0.5f

        /** Creates new instance of [BubbleStashController] */
        @JvmStatic
        fun newInstance(
            taskbarHotseatDimensionsProvider: TaskbarHotseatDimensionsProvider
        ): BubbleStashController {
            return PersistentTaskbarStashController(taskbarHotseatDimensionsProvider)
        }
    }
}
+223 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.launcher3.taskbar.bubbles.stashing

import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.animation.AnimatorSet
import android.view.MotionEvent
import android.view.View
import com.android.launcher3.anim.AnimatedFloat
import com.android.launcher3.taskbar.TaskbarInsetsController
import com.android.launcher3.taskbar.bubbles.BubbleBarViewController
import com.android.launcher3.taskbar.bubbles.BubbleStashedHandleViewController
import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController.Companion.BAR_STASH_DURATION
import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController.Companion.BAR_TRANSLATION_DURATION
import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController.ControllersAfterInitAction
import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController.TaskbarHotseatDimensionsProvider
import com.android.launcher3.util.MultiPropertyFactory
import com.android.wm.shell.common.bubbles.BubbleBarLocation
import com.android.wm.shell.shared.animation.PhysicsAnimator

class PersistentTaskbarStashController(
    private val taskbarHotseatDimensionsProvider: TaskbarHotseatDimensionsProvider,
) : BubbleStashController {

    private lateinit var taskbarInsetsController: TaskbarInsetsController
    private lateinit var bubbleBarViewController: BubbleBarViewController
    private lateinit var bubbleBarTranslationYAnimator: AnimatedFloat
    private lateinit var bubbleBarAlphaAnimator: MultiPropertyFactory<View>.MultiProperty
    private lateinit var bubbleBarScaleAnimator: AnimatedFloat
    private lateinit var controllersAfterInitAction: ControllersAfterInitAction

    override var isBubblesShowingOnHome: Boolean = false
        set(onHome) {
            if (field == onHome) return
            field = onHome
            if (!bubbleBarViewController.hasBubbles()) {
                // if there are no bubbles, there's nothing to show, so just return.
                return
            }
            if (onHome) {
                // When transition to home we should show collapse the bubble bar
                updateStashedAndExpandedState(stash = false, expand = false)
            }
            animateBubbleBarY()
            bubbleBarViewController.onBubbleBarConfigurationChanged(/* animate= */ true)
        }

    override var isBubblesShowingOnOverview: Boolean = false
        set(onOverview) {
            if (field == onOverview) return
            field = onOverview
            if (!onOverview) {
                // When transition from overview we should show collapse the bubble bar
                updateStashedAndExpandedState(stash = false, expand = false)
            }
            bubbleBarViewController.onBubbleBarConfigurationChanged(/* animate= */ true)
        }

    override var isSysuiLocked: Boolean = false
        set(isLocked) {
            if (field == isLocked) return
            field = isLocked
            if (!isLocked && bubbleBarViewController.hasBubbles()) {
                animateAfterUnlock()
            }
        }

    override var isTransientTaskBar: Boolean = false

    /** When the bubble bar is shown for the persistent task bar, there is no handle view. */
    override val hasHandleView: Boolean = false

    /** For persistent task bar we never stash the bubble bar */
    override val isStashed: Boolean = false

    override val bubbleBarTranslationYForTaskbar: Float
        get() {
            val taskbarBottomMargin = taskbarHotseatDimensionsProvider.getTaskbarBottomSpace()
            val bubbleBarHeight: Float = bubbleBarViewController.bubbleBarCollapsedHeight
            val taskbarHeight = taskbarHotseatDimensionsProvider.getTaskbarHeight()
            return -taskbarBottomMargin - (taskbarHeight - bubbleBarHeight) / 2f
        }

    override val bubbleBarTranslationYForHotseat: Float
        get() {
            val hotseatBottomSpace = taskbarHotseatDimensionsProvider.getHotseatBottomSpace()
            val hotseatCellHeight = taskbarHotseatDimensionsProvider.getHotseatHeight()
            val bubbleBarHeight: Float = bubbleBarViewController.bubbleBarCollapsedHeight
            return -hotseatBottomSpace - (hotseatCellHeight - bubbleBarHeight) / 2
        }

    override fun init(
        taskbarInsetsController: TaskbarInsetsController,
        bubbleBarViewController: BubbleBarViewController,
        bubbleStashedHandleViewController: BubbleStashedHandleViewController?,
        controllersAfterInitAction: ControllersAfterInitAction
    ) {
        this.taskbarInsetsController = taskbarInsetsController
        this.bubbleBarViewController = bubbleBarViewController
        this.controllersAfterInitAction = controllersAfterInitAction
        bubbleBarTranslationYAnimator = bubbleBarViewController.bubbleBarTranslationY
        bubbleBarAlphaAnimator = bubbleBarViewController.bubbleBarAlpha.get(0)
        bubbleBarScaleAnimator = bubbleBarViewController.bubbleBarScale
    }

    private fun animateAfterUnlock() {
        val animatorSet = AnimatorSet()
        if (isBubblesShowingOnHome || isBubblesShowingOnOverview) {
            animatorSet.playTogether(
                bubbleBarScaleAnimator.animateToValue(1f),
                bubbleBarTranslationYAnimator.animateToValue(bubbleBarTranslationY),
                bubbleBarAlphaAnimator.animateToValue(1f)
            )
        }
        updateTouchRegionOnAnimationEnd(animatorSet)
        animatorSet.setDuration(BAR_STASH_DURATION).start()
    }

    override fun updateStashedAndExpandedState(stash: Boolean, expand: Boolean) {
        if (bubbleBarViewController.isHiddenForNoBubbles) {
            // If there are no bubbles the bar is invisible, nothing to do here.
            return
        }
        if (bubbleBarViewController.isExpanded != expand) {
            bubbleBarViewController.isExpanded = expand
        }
    }

    override fun showBubbleBarImmediate() = showBubbleBarImmediate(bubbleBarTranslationY)

    override fun showBubbleBarImmediate(bubbleBarTranslationY: Float) {
        bubbleBarTranslationYAnimator.updateValue(bubbleBarTranslationY)
        bubbleBarAlphaAnimator.setValue(1f)
        bubbleBarScaleAnimator.updateValue(1f)
    }

    override fun setBubbleBarLocation(bubbleBarLocation: BubbleBarLocation) {
        // When the bubble bar is shown for the persistent task bar, there is no handle view, so no
        // operation is performed.
    }

    override fun stashBubbleBarImmediate() {
        // When the bubble bar is shown for the persistent task bar, there is no handle view, so no
        // operation is performed.
    }

    /** If bubble bar is visible return bubble bar height, 0 otherwise */
    override fun getTouchableHeight() =
        if (isBubbleBarVisible()) {
            bubbleBarViewController.bubbleBarCollapsedHeight.toInt()
        } else {
            0
        }

    override fun isBubbleBarVisible(): Boolean = bubbleBarViewController.hasBubbles()

    override fun onNewBubbleAnimationInterrupted(isStashed: Boolean, bubbleBarTranslationY: Float) {
        showBubbleBarImmediate(bubbleBarTranslationY)
    }

    override fun isEventOverBubbleBarViews(ev: MotionEvent): Boolean =
        bubbleBarViewController.isEventOverAnyItem(ev)

    override fun getSlideInAnimationDistanceY(): Float {
        // distance from the bottom of the screen and the bubble bar center.
        return -bubbleBarViewController.bubbleBarCollapsedHeight / 2f
    }

    /** When the bubble bar is shown for the persistent task bar, there is no handle view. */
    override fun getStashedHandleTranslationForNewBubbleAnimation(): Float = 0f

    /** When the bubble bar is shown for the persistent task bar, there is no handle view. */
    override fun getStashedHandlePhysicsAnimator(): PhysicsAnimator<View>? = null

    override fun updateTaskbarTouchRegion() {
        taskbarInsetsController.onTaskbarOrBubblebarWindowHeightOrInsetsChanged()
    }

    /**
     * When the bubble bar is shown for the persistent task bar the bar does not stash, so no
     * operation is performed
     */
    override fun setHandleTranslationY(translationY: Float) {
        // no op since does not have a handle view
    }

    /** Animates bubble bar Y accordingly to the showing mode */
    private fun animateBubbleBarY() {
        val animator =
            bubbleBarViewController.bubbleBarTranslationY.animateToValue(bubbleBarTranslationY)
        updateTouchRegionOnAnimationEnd(animator)
        animator.setDuration(BAR_TRANSLATION_DURATION)
        animator.start()
    }

    private fun updateTouchRegionOnAnimationEnd(animator: Animator) {
        animator.addListener(
            object : AnimatorListenerAdapter() {

                override fun onAnimationEnd(animation: Animator) {
                    controllersAfterInitAction.runAfterInit {
                        taskbarInsetsController.onTaskbarOrBubblebarWindowHeightOrInsetsChanged()
                    }
                }
            }
        )
    }
}
+256 −0

File added.

Preview size limit exceeded, changes collapsed.

+38 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.launcher3.taskbar.bubbles.stashing

class ImmediateAction : BubbleStashController.ControllersAfterInitAction {
    override fun runAfterInit(action: () -> Unit) = action.invoke()
}

class DefaultDimensionsProvider : BubbleStashController.TaskbarHotseatDimensionsProvider {
    override fun getTaskbarBottomSpace(): Int = TASKBAR_BOTTOM_SPACE

    override fun getTaskbarHeight(): Int = TASKBAR_HEIGHT

    override fun getHotseatBottomSpace(): Int = HOTSEAT_BOTTOM_SPACE

    override fun getHotseatHeight(): Int = HOTSEAT_HEIGHT

    companion object {
        const val TASKBAR_BOTTOM_SPACE = 0
        const val TASKBAR_HEIGHT = 110
        const val HOTSEAT_BOTTOM_SPACE = 20
        const val HOTSEAT_HEIGHT = 150
    }
}