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

Commit 8ef4cf5b authored by Jordan Demeulenaere's avatar Jordan Demeulenaere
Browse files

Polish status bar launch animations.

This CL improves the ongoing call animation by:

1. Making sure that the status bar window matches its parent size during
   the animation, so that the expanding view is not clipped.
2. Expanding the view below the other status bar text.

See b/183229367#comment8 and #comment11 for before/after videos.

Bug: 183229367
Test: Create an ongoing call notification, tap it
Change-Id: Idfd8a43109584a4b21ad0a3e5f5e2028a87a9c60
parent 969eda42
Loading
Loading
Loading
Loading
+18 −13
Original line number Original line Diff line number Diff line
@@ -17,6 +17,7 @@ import android.view.RemoteAnimationAdapter
import android.view.RemoteAnimationTarget
import android.view.RemoteAnimationTarget
import android.view.SyncRtSurfaceTransactionApplier
import android.view.SyncRtSurfaceTransactionApplier
import android.view.View
import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
import android.view.WindowManager
import android.view.animation.AnimationUtils
import android.view.animation.AnimationUtils
import android.view.animation.PathInterpolator
import android.view.animation.PathInterpolator
@@ -112,7 +113,7 @@ class ActivityLaunchAnimator(context: Context) {
    @PublishedApi
    @PublishedApi
    internal fun Controller.callOnIntentStartedOnMainThread(willAnimate: Boolean) {
    internal fun Controller.callOnIntentStartedOnMainThread(willAnimate: Boolean) {
        if (Looper.myLooper() != Looper.getMainLooper()) {
        if (Looper.myLooper() != Looper.getMainLooper()) {
            this.getRootView().context.mainExecutor.execute {
            this.launchContainer.context.mainExecutor.execute {
                this.onIntentStarted(willAnimate)
                this.onIntentStarted(willAnimate)
            }
            }
        } else {
        } else {
@@ -166,15 +167,19 @@ class ActivityLaunchAnimator(context: Context) {
        }
        }


        /**
        /**
         * Return the root [View] that contains the view that started the intent and will be
         * The container in which the view that started the intent will be animating together with
         * animating together with the window.
         * the opening window.
         *
         *
         * This view will be used to:
         * This will be used to:
         *  - Get the associated [Context].
         *  - Get the associated [Context].
         *  - Compute whether we are expanding fully above the current window.
         *  - Compute whether we are expanding fully above the current window.
         *  - Apply surface transactions in sync with RenderThread.
         *  - Apply surface transactions in sync with RenderThread.
         *
         * This container can be changed to force this [Controller] to animate the expanding view
         * inside a different location, for instance to ensure correct layering during the
         * animation.
         */
         */
        fun getRootView(): View
        var launchContainer: ViewGroup


        /**
        /**
         * Return the [State] of the view that will be animated. We will animate from this state to
         * Return the [State] of the view that will be animated. We will animate from this state to
@@ -272,9 +277,9 @@ class ActivityLaunchAnimator(context: Context) {


    @VisibleForTesting
    @VisibleForTesting
    inner class Runner(private val controller: Controller) : IRemoteAnimationRunner.Stub() {
    inner class Runner(private val controller: Controller) : IRemoteAnimationRunner.Stub() {
        private val rootView = controller.getRootView()
        private val launchContainer = controller.launchContainer
        @PublishedApi internal val context = rootView.context
        @PublishedApi internal val context = launchContainer.context
        private val transactionApplier = SyncRtSurfaceTransactionApplier(rootView)
        private val transactionApplier = SyncRtSurfaceTransactionApplier(launchContainer)
        private var animator: ValueAnimator? = null
        private var animator: ValueAnimator? = null


        private var windowCrop = Rect()
        private var windowCrop = Rect()
@@ -291,11 +296,11 @@ class ActivityLaunchAnimator(context: Context) {


        @PublishedApi
        @PublishedApi
        internal fun postTimeout() {
        internal fun postTimeout() {
            rootView.postDelayed(onTimeout, LAUNCH_TIMEOUT)
            launchContainer.postDelayed(onTimeout, LAUNCH_TIMEOUT)
        }
        }


        private fun removeTimeout() {
        private fun removeTimeout() {
            rootView.removeCallbacks(onTimeout)
            launchContainer.removeCallbacks(onTimeout)
        }
        }


        override fun onAnimationStart(
        override fun onAnimationStart(
@@ -369,11 +374,11 @@ class ActivityLaunchAnimator(context: Context) {
            val endWidth = endRight - endLeft
            val endWidth = endRight - endLeft


            // TODO(b/184121838): Ensure that we are launching on the same screen.
            // TODO(b/184121838): Ensure that we are launching on the same screen.
            val rootViewLocation = rootView.locationOnScreen
            val rootViewLocation = launchContainer.locationOnScreen
            val isExpandingFullyAbove = endTop <= rootViewLocation[1] &&
            val isExpandingFullyAbove = endTop <= rootViewLocation[1] &&
                endBottom >= rootViewLocation[1] + rootView.height &&
                endBottom >= rootViewLocation[1] + launchContainer.height &&
                endLeft <= rootViewLocation[0] &&
                endLeft <= rootViewLocation[0] &&
                endRight >= rootViewLocation[0] + rootView.width
                endRight >= rootViewLocation[0] + launchContainer.width


            // TODO(b/184121838): We should somehow get the top and bottom radius of the window.
            // TODO(b/184121838): We should somehow get the top and bottom radius of the window.
            val endRadius = if (isExpandingFullyAbove) {
            val endRadius = if (isExpandingFullyAbove) {
+10 −0
Original line number Original line Diff line number Diff line
package com.android.systemui.animation

/**
 * A base class to easily create an implementation of [ActivityLaunchAnimator.Controller] which
 * delegates most of its call to [delegate]. This is mostly useful for Java code which can't easily
 * create such a delegated class.
 */
open class DelegateLaunchAnimatorController(
    protected val delegate: ActivityLaunchAnimator.Controller
) : ActivityLaunchAnimator.Controller by delegate
 No newline at end of file
+10 −12
Original line number Original line Diff line number Diff line
@@ -14,6 +14,7 @@ import android.graphics.drawable.LayerDrawable
import android.view.GhostView
import android.view.GhostView
import android.view.View
import android.view.View
import android.view.ViewGroup
import android.view.ViewGroup
import android.view.ViewGroupOverlay
import android.widget.FrameLayout
import android.widget.FrameLayout
import kotlin.math.min
import kotlin.math.min


@@ -32,9 +33,10 @@ open class GhostedViewLaunchAnimatorController(
    /** The view that will be ghosted and from which the background will be extracted. */
    /** The view that will be ghosted and from which the background will be extracted. */
    private val ghostedView: View
    private val ghostedView: View
) : ActivityLaunchAnimator.Controller {
) : ActivityLaunchAnimator.Controller {
    /** The root view to which we will add the ghost view and expanding background. */
    /** The container to which we will add the ghost view and expanding background. */
    private val rootView = ghostedView.rootView as ViewGroup
    override var launchContainer = ghostedView.rootView as ViewGroup
    private val rootViewOverlay = rootView.overlay
    private val launchContainerOverlay: ViewGroupOverlay
        get() = launchContainer.overlay


    /** The ghost view that is drawn and animated instead of the ghosted view. */
    /** The ghost view that is drawn and animated instead of the ghosted view. */
    private var ghostView: GhostView? = null
    private var ghostView: GhostView? = null
@@ -42,7 +44,7 @@ open class GhostedViewLaunchAnimatorController(
    private val ghostViewMatrix = Matrix()
    private val ghostViewMatrix = Matrix()


    /**
    /**
     * The expanding background view that will be added to [rootView] (below [ghostView]) and
     * The expanding background view that will be added to [launchContainer] (below [ghostView]) and
     * animate.
     * animate.
     */
     */
    private var backgroundView: FrameLayout? = null
    private var backgroundView: FrameLayout? = null
@@ -96,10 +98,6 @@ open class GhostedViewLaunchAnimatorController(
        return gradient.cornerRadii?.get(CORNER_RADIUS_BOTTOM_INDEX) ?: gradient.cornerRadius
        return gradient.cornerRadii?.get(CORNER_RADIUS_BOTTOM_INDEX) ?: gradient.cornerRadius
    }
    }


    override fun getRootView(): View {
        return rootView
    }

    override fun createAnimatorState(): ActivityLaunchAnimator.State {
    override fun createAnimatorState(): ActivityLaunchAnimator.State {
        val location = ghostedView.locationOnScreen
        val location = ghostedView.locationOnScreen
        return ActivityLaunchAnimator.State(
        return ActivityLaunchAnimator.State(
@@ -113,10 +111,10 @@ open class GhostedViewLaunchAnimatorController(
    }
    }


    override fun onLaunchAnimationStart(isExpandingFullyAbove: Boolean) {
    override fun onLaunchAnimationStart(isExpandingFullyAbove: Boolean) {
        backgroundView = FrameLayout(rootView.context).apply {
        backgroundView = FrameLayout(launchContainer.context).apply {
            forceHasOverlappingRendering(false)
            forceHasOverlappingRendering(false)
        }
        }
        rootViewOverlay.add(backgroundView)
        launchContainerOverlay.add(backgroundView)


        // We wrap the ghosted view background and use it to draw the expandable background. Its
        // We wrap the ghosted view background and use it to draw the expandable background. Its
        // alpha will be set to 0 as soon as we start drawing the expanding background.
        // alpha will be set to 0 as soon as we start drawing the expanding background.
@@ -127,7 +125,7 @@ open class GhostedViewLaunchAnimatorController(


        // Create a ghost of the view that will be moving and fading out. This allows to fade out
        // Create a ghost of the view that will be moving and fading out. This allows to fade out
        // the content before fading out the background.
        // the content before fading out the background.
        ghostView = GhostView.addGhost(ghostedView, rootView).apply {
        ghostView = GhostView.addGhost(ghostedView, launchContainer).apply {
            setLayerType(View.LAYER_TYPE_HARDWARE, null)
            setLayerType(View.LAYER_TYPE_HARDWARE, null)
        }
        }


@@ -169,7 +167,7 @@ open class GhostedViewLaunchAnimatorController(
        backgroundDrawable?.wrapped?.alpha = startBackgroundAlpha
        backgroundDrawable?.wrapped?.alpha = startBackgroundAlpha


        GhostView.removeGhost(ghostedView)
        GhostView.removeGhost(ghostedView)
        rootViewOverlay.remove(backgroundView)
        launchContainerOverlay.remove(backgroundView)
        ghostedView.invalidate()
        ghostedView.invalidate()
    }
    }


+5 −0
Original line number Original line Diff line number Diff line
@@ -25,6 +25,11 @@
    android:layout_height="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true">
    android:fitsSystemWindows="true">


    <FrameLayout
        android:id="@+id/status_bar_launch_animation_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <FrameLayout
    <FrameLayout
        android:id="@+id/status_bar_container"
        android:id="@+id/status_bar_container"
        android:layout_width="match_parent"
        android:layout_width="match_parent"
+6 −2
Original line number Original line Diff line number Diff line
package com.android.systemui.statusbar.notification
package com.android.systemui.statusbar.notification


import android.view.View
import android.view.ViewGroup
import com.android.internal.jank.InteractionJankMonitor
import com.android.internal.jank.InteractionJankMonitor
import com.android.systemui.animation.ActivityLaunchAnimator
import com.android.systemui.animation.ActivityLaunchAnimator
import com.android.systemui.statusbar.NotificationShadeDepthController
import com.android.systemui.statusbar.NotificationShadeDepthController
@@ -45,7 +45,11 @@ class NotificationLaunchAnimatorController(
) : ActivityLaunchAnimator.Controller {
) : ActivityLaunchAnimator.Controller {
    private val notificationKey = notification.entry.sbn.key
    private val notificationKey = notification.entry.sbn.key


    override fun getRootView(): View = notification.rootView
    override var launchContainer: ViewGroup
        get() = notification.rootView as ViewGroup
        set(ignored) {
            // Do nothing. Notifications are always animated inside their rootView.
        }


    override fun createAnimatorState(): ActivityLaunchAnimator.State {
    override fun createAnimatorState(): ActivityLaunchAnimator.State {
        // If the notification panel is collapsed, the clip may be larger than the height.
        // If the notification panel is collapsed, the clip may be larger than the height.
Loading