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

Commit c0a85b7c authored by Jordan Demeulenaere's avatar Jordan Demeulenaere
Browse files

Split ActivityLaunchAnimator (1/2)

This CL splits ActivityLaunchAnimator by extracting common logic into
LaunchAnimator. The goal of this CL is to be able to reuse the
LaunchAnimator logic for dialog launches.

This CL also improves GhostedViewLaunchAnimator such that it also works
with:
 * launch containers that are not located at (0, 0).
 * ghosted views that move.

Test: atest ActivityLaunchAnimatorTest
Bug: 193634619
Change-Id: Ic05603600d4a7d4e27182c79bef54286087d00d0
parent a83e90e0
Loading
Loading
Loading
Loading
+4 −0
Original line number Original line Diff line number Diff line
@@ -165,6 +165,10 @@ public final class MathUtils {
        return start + (stop - start) * amount;
        return start + (stop - start) * amount;
    }
    }


    public static float lerp(int start, int stop, float amount) {
        return lerp((float) start, (float) stop, amount);
    }

    /**
    /**
     * Returns the interpolation scalar (s) that satisfies the equation: {@code value = }{@link
     * Returns the interpolation scalar (s) that satisfies the equation: {@code value = }{@link
     * #lerp}{@code (a, b, s)}
     * #lerp}{@code (a, b, s)}
+79 −306
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2021 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.systemui.animation
package com.android.systemui.animation


import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.animation.ValueAnimator
import android.app.ActivityManager
import android.app.ActivityManager
import android.app.ActivityTaskManager
import android.app.ActivityTaskManager
import android.app.PendingIntent
import android.app.PendingIntent
import android.app.TaskInfo
import android.app.TaskInfo
import android.content.Context
import android.graphics.Matrix
import android.graphics.Matrix
import android.graphics.PorterDuff
import android.graphics.PorterDuffXfermode
import android.graphics.Rect
import android.graphics.Rect
import android.graphics.RectF
import android.graphics.RectF
import android.graphics.drawable.GradientDrawable
import android.os.Looper
import android.os.Looper
import android.os.RemoteException
import android.os.RemoteException
import android.util.Log
import android.util.Log
import android.util.MathUtils
import android.view.IRemoteAnimationFinishedCallback
import android.view.IRemoteAnimationFinishedCallback
import android.view.IRemoteAnimationRunner
import android.view.IRemoteAnimationRunner
import android.view.RemoteAnimationAdapter
import android.view.RemoteAnimationAdapter
@@ -26,7 +34,6 @@ import android.view.SyncRtSurfaceTransactionApplier
import android.view.View
import android.view.View
import android.view.ViewGroup
import android.view.ViewGroup
import android.view.WindowManager
import android.view.WindowManager
import android.view.animation.AnimationUtils
import android.view.animation.PathInterpolator
import android.view.animation.PathInterpolator
import com.android.internal.annotations.VisibleForTesting
import com.android.internal.annotations.VisibleForTesting
import com.android.internal.policy.ScreenDecorationsUtils
import com.android.internal.policy.ScreenDecorationsUtils
@@ -38,52 +45,23 @@ private const val TAG = "ActivityLaunchAnimator"
 * A class that allows activities to be started in a seamless way from a view that is transforming
 * A class that allows activities to be started in a seamless way from a view that is transforming
 * nicely into the starting window.
 * nicely into the starting window.
 */
 */
class ActivityLaunchAnimator(
class ActivityLaunchAnimator(private val launchAnimator: LaunchAnimator) {
    private val callback: Callback,
    context: Context
) {
    companion object {
    companion object {
        private const val DEBUG = false
        const val ANIMATION_DURATION = 500L
        private const val ANIMATION_DURATION_FADE_OUT_CONTENT = 150L
        private const val ANIMATION_DURATION_FADE_IN_WINDOW = 183L
        private const val ANIMATION_DELAY_FADE_IN_WINDOW = ANIMATION_DURATION_FADE_OUT_CONTENT
        private const val ANIMATION_DURATION_NAV_FADE_IN = 266L
        private const val ANIMATION_DURATION_NAV_FADE_IN = 266L
        private const val ANIMATION_DURATION_NAV_FADE_OUT = 133L
        private const val ANIMATION_DURATION_NAV_FADE_OUT = 133L
        private const val ANIMATION_DELAY_NAV_FADE_IN =
        private const val ANIMATION_DELAY_NAV_FADE_IN =
                ANIMATION_DURATION - ANIMATION_DURATION_NAV_FADE_IN
            LaunchAnimator.ANIMATION_DURATION - ANIMATION_DURATION_NAV_FADE_IN
        private const val LAUNCH_TIMEOUT = 1000L
        private const val LAUNCH_TIMEOUT = 1000L


        @JvmField val CONTENT_FADE_OUT_INTERPOLATOR = PathInterpolator(0f, 0f, 0.2f, 1f)
        private val WINDOW_FADE_IN_INTERPOLATOR = PathInterpolator(0f, 0f, 0.6f, 1f)
        private val NAV_FADE_IN_INTERPOLATOR = PathInterpolator(0f, 0f, 0f, 1f)
        private val NAV_FADE_IN_INTERPOLATOR = PathInterpolator(0f, 0f, 0f, 1f)
        private val NAV_FADE_OUT_INTERPOLATOR = PathInterpolator(0.2f, 0f, 1f, 1f)
        private val NAV_FADE_OUT_INTERPOLATOR = PathInterpolator(0.2f, 0f, 1f, 1f)

    }
        private val SRC_MODE = PorterDuffXfermode(PorterDuff.Mode.SRC)


    /**
    /**
         * Given the [linearProgress] of a launch animation, return the linear progress of the
     * The callback of this animator. This should be set before any call to
         * sub-animation starting [delay] ms after the launch animation and that lasts [duration].
     * [start(Pending)IntentWithAnimation].
     */
     */
        @JvmStatic
    var callback: Callback? = null
        fun getProgress(linearProgress: Float, delay: Long, duration: Long): Float {
            return MathUtils.constrain(
                    (linearProgress * ANIMATION_DURATION - delay) / duration,
                    0.0f,
                    1.0f
            )
        }
    }

    /** The interpolator used for the width, height, Y position and corner radius. */
    private val animationInterpolator = AnimationUtils.loadInterpolator(context,
            R.interpolator.launch_animation_interpolator_y)

    /** The interpolator used for the X position. */
    private val animationInterpolatorX = AnimationUtils.loadInterpolator(context,
            R.interpolator.launch_animation_interpolator_x)

    private val cornerRadii = FloatArray(8)


    /**
    /**
     * Start an intent and animate the opening window. The intent will be started by running
     * Start an intent and animate the opening window. The intent will be started by running
@@ -119,6 +97,8 @@ class ActivityLaunchAnimator(
            return
            return
        }
        }


        val callback = this.callback ?: throw IllegalStateException(
            "ActivityLaunchAnimator.callback must be set before using this animator")
        val runner = Runner(controller)
        val runner = Runner(controller)
        val hideKeyguardWithAnimation = callback.isOnKeyguard() && !showOverLockscreen
        val hideKeyguardWithAnimation = callback.isOnKeyguard() && !showOverLockscreen


@@ -127,8 +107,8 @@ class ActivityLaunchAnimator(
        val animationAdapter = if (!hideKeyguardWithAnimation) {
        val animationAdapter = if (!hideKeyguardWithAnimation) {
            RemoteAnimationAdapter(
            RemoteAnimationAdapter(
                runner,
                runner,
                    ANIMATION_DURATION,
                LaunchAnimator.ANIMATION_DURATION,
                    ANIMATION_DURATION - 150 /* statusBarTransitionDelay */
                LaunchAnimator.ANIMATION_DURATION - 150 /* statusBarTransitionDelay */
            )
            )
        } else {
        } else {
            null
            null
@@ -234,7 +214,7 @@ class ActivityLaunchAnimator(
     *
     *
     * Note that all callbacks (onXXX methods) are all called on the main thread.
     * Note that all callbacks (onXXX methods) are all called on the main thread.
     */
     */
    interface Controller {
    interface Controller : LaunchAnimator.Controller {
        companion object {
        companion object {
            /**
            /**
             * Return a [Controller] that will animate and expand [view] into the opening window.
             * Return a [Controller] that will animate and expand [view] into the opening window.
@@ -258,53 +238,12 @@ class ActivityLaunchAnimator(
            }
            }
        }
        }


        /**
         * The container in which the view that started the intent will be animating together with
         * the opening window.
         *
         * This will be used to:
         *  - Get the associated [Context].
         *  - Compute whether we are expanding fully above the current window.
         *  - 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.
         */
        var launchContainer: ViewGroup

        /**
         * Return the [State] of the view that will be animated. We will animate from this state to
         * the final window state.
         *
         * Note: This state will be mutated and passed to [onLaunchAnimationProgress] during the
         * animation.
         */
        fun createAnimatorState(): State

        /**
        /**
         * The intent was started. If [willAnimate] is false, nothing else will happen and the
         * The intent was started. If [willAnimate] is false, nothing else will happen and the
         * animation will not be started.
         * animation will not be started.
         */
         */
        fun onIntentStarted(willAnimate: Boolean) {}
        fun onIntentStarted(willAnimate: Boolean) {}


        /**
         * The animation started. This is typically used to initialize any additional resource
         * needed for the animation. [isExpandingFullyAbove] will be true if the window is expanding
         * fully above the [root view][getRootView].
         */
        fun onLaunchAnimationStart(isExpandingFullyAbove: Boolean) {}

        /** The animation made progress and the expandable view [state] should be updated. */
        fun onLaunchAnimationProgress(state: State, progress: Float, linearProgress: Float) {}

        /**
         * The animation ended. This will be called *if and only if* [onLaunchAnimationStart] was
         * called previously. This is typically used to clean up the resources initialized when the
         * animation was started.
         */
        fun onLaunchAnimationEnd(isExpandingFullyAbove: Boolean) {}

        /**
        /**
         * The animation was cancelled. Note that [onLaunchAnimationEnd] will still be called after
         * The animation was cancelled. Note that [onLaunchAnimationEnd] will still be called after
         * this if the animation was already started, i.e. if [onLaunchAnimationStart] was called
         * this if the animation was already started, i.e. if [onLaunchAnimationStart] was called
@@ -313,66 +252,11 @@ class ActivityLaunchAnimator(
        fun onLaunchAnimationCancelled() {}
        fun onLaunchAnimationCancelled() {}
    }
    }


    /** The state of an expandable view during an [ActivityLaunchAnimator] animation. */
    open class State(
        /** The position of the view in screen space coordinates. */
        var top: Int,
        var bottom: Int,
        var left: Int,
        var right: Int,

        var topCornerRadius: Float = 0f,
        var bottomCornerRadius: Float = 0f
    ) {
        private val startTop = top
        private val startBottom = bottom
        private val startLeft = left
        private val startRight = right
        private val startWidth = width
        private val startHeight = height
        val startCenterX = centerX
        val startCenterY = centerY

        val width: Int
            get() = right - left

        val height: Int
            get() = bottom - top

        open val topChange: Int
            get() = top - startTop

        open val bottomChange: Int
            get() = bottom - startBottom

        val leftChange: Int
            get() = left - startLeft

        val rightChange: Int
            get() = right - startRight

        val widthRatio: Float
            get() = width.toFloat() / startWidth

        val heightRatio: Float
            get() = height.toFloat() / startHeight

        val centerX: Float
            get() = left + width / 2f

        val centerY: Float
            get() = top + height / 2f

        /** Whether the expanded view should be visible or hidden. */
        var visible: Boolean = true
    }

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


        private val matrix = Matrix()
        private val matrix = Matrix()
        private val invertMatrix = Matrix()
        private val invertMatrix = Matrix()
@@ -380,6 +264,7 @@ class ActivityLaunchAnimator(
        private var windowCropF = RectF()
        private var windowCropF = RectF()
        private var timedOut = false
        private var timedOut = false
        private var cancelled = false
        private var cancelled = false
        private var animation: LaunchAnimator.Animation? = null


        // A timeout to cancel the remote animation if it is not started within X milliseconds after
        // A timeout to cancel the remote animation if it is not started within X milliseconds after
        // the intent was started.
        // the intent was started.
@@ -429,7 +314,7 @@ class ActivityLaunchAnimator(
            nonApps: Array<out RemoteAnimationTarget>?,
            nonApps: Array<out RemoteAnimationTarget>?,
            iCallback: IRemoteAnimationFinishedCallback?
            iCallback: IRemoteAnimationFinishedCallback?
        ) {
        ) {
            if (DEBUG) {
            if (LaunchAnimator.DEBUG) {
                Log.d(TAG, "Remote animation started")
                Log.d(TAG, "Remote animation started")
            }
            }


@@ -449,36 +334,20 @@ class ActivityLaunchAnimator(
                it.windowType == WindowManager.LayoutParams.TYPE_NAVIGATION_BAR
                it.windowType == WindowManager.LayoutParams.TYPE_NAVIGATION_BAR
            }
            }


            // Start state.
            val state = controller.createAnimatorState()

            val startTop = state.top
            val startBottom = state.bottom
            val startLeft = state.left
            val startRight = state.right
            val startXCenter = (startLeft + startRight) / 2f
            val startWidth = startRight - startLeft

            val startTopCornerRadius = state.topCornerRadius
            val startBottomCornerRadius = state.bottomCornerRadius

            // End state.
            val windowBounds = window.screenSpaceBounds
            val windowBounds = window.screenSpaceBounds
            val endTop = windowBounds.top
            val endState = LaunchAnimator.State(
            val endBottom = windowBounds.bottom
                top = windowBounds.top,
            val endLeft = windowBounds.left
                bottom = windowBounds.bottom,
            val endRight = windowBounds.right
                left = windowBounds.left,
            val endXCenter = (endLeft + endRight) / 2f
                right = windowBounds.right
            val endWidth = endRight - endLeft
            )

            val callback = this@ActivityLaunchAnimator.callback!!
            // TODO(b/184121838): Ensure that we are launching on the same screen.
            val windowBackgroundColor = callback.getBackgroundColor(window.taskInfo)
            val rootViewLocation = launchContainer.locationOnScreen

            val isExpandingFullyAbove = endTop <= rootViewLocation[1] &&
            // TODO(b/184121838): We should somehow get the top and bottom radius of the window
                endBottom >= rootViewLocation[1] + launchContainer.height &&
            // instead of recomputing isExpandingFullyAbove here.
                endLeft <= rootViewLocation[0] &&
            val isExpandingFullyAbove =
                endRight >= rootViewLocation[0] + launchContainer.width
                launchAnimator.isExpandingFullyAbove(controller.launchContainer, endState)

            // TODO(b/184121838): We should somehow get the top and bottom radius of the window.
            val endRadius = if (isExpandingFullyAbove) {
            val endRadius = if (isExpandingFullyAbove) {
                // Most of the time, expanding fully above the root view means expanding in full
                // Most of the time, expanding fully above the root view means expanding in full
                // screen.
                // screen.
@@ -488,97 +357,40 @@ class ActivityLaunchAnimator(
                // a radius of 0.
                // a radius of 0.
                0f
                0f
            }
            }
            endState.topCornerRadius = endRadius
            endState.bottomCornerRadius = endRadius


            // We add an extra layer with the same color as the app splash screen background color,
            // We animate the opening window and delegate the view expansion to [this.controller].
            // which is usually the same color of the app background. We first fade in this layer
            val delegate = this.controller
            // to hide the expanding view, then we fade it out with SRC mode to draw a hole in the
            val controller = object : LaunchAnimator.Controller by delegate {
            // launch container and reveal the opening window.
                override fun onLaunchAnimationStart(isExpandingFullyAbove: Boolean) {
            val windowBackgroundColor = callback.getBackgroundColor(window.taskInfo)
            val windowBackgroundLayer = GradientDrawable().apply {
                setColor(windowBackgroundColor)
                alpha = 0
            }

            // Update state.
            val animator = ValueAnimator.ofFloat(0f, 1f)
            this.animator = animator
            animator.duration = ANIMATION_DURATION
            animator.interpolator = Interpolators.LINEAR

            val launchContainerOverlay = launchContainer.overlay
            animator.addListener(object : AnimatorListenerAdapter() {
                override fun onAnimationStart(animation: Animator?, isReverse: Boolean) {
                    if (DEBUG) {
                        Log.d(TAG, "Animation started")
                    }

                    callback.setBlursDisabledForAppLaunch(true)
                    callback.setBlursDisabledForAppLaunch(true)
                    controller.onLaunchAnimationStart(isExpandingFullyAbove)
                    delegate.onLaunchAnimationStart(isExpandingFullyAbove)

                    // Add the drawable to the launch container overlay. Overlays always draw
                    // drawables after views, so we know that it will be drawn above any view added
                    // by the controller.
                    launchContainerOverlay.add(windowBackgroundLayer)
                }

                override fun onAnimationEnd(animation: Animator?) {
                    if (DEBUG) {
                        Log.d(TAG, "Animation ended")
                }
                }


                override fun onLaunchAnimationEnd(isExpandingFullyAbove: Boolean) {
                    callback.setBlursDisabledForAppLaunch(false)
                    callback.setBlursDisabledForAppLaunch(false)
                    iCallback?.invoke()
                    iCallback?.invoke()
                    controller.onLaunchAnimationEnd(isExpandingFullyAbove)
                    delegate.onLaunchAnimationEnd(isExpandingFullyAbove)
                    launchContainerOverlay.remove(windowBackgroundLayer)
                }
                }
            })

            animator.addUpdateListener { animation ->
                if (cancelled) {
                    return@addUpdateListener
                }

                val linearProgress = animation.animatedFraction
                val progress = animationInterpolator.getInterpolation(linearProgress)
                val xProgress = animationInterpolatorX.getInterpolation(linearProgress)
                val xCenter = MathUtils.lerp(startXCenter, endXCenter, xProgress)
                val halfWidth = lerp(startWidth, endWidth, progress) / 2

                state.top = lerp(startTop, endTop, progress).roundToInt()
                state.bottom = lerp(startBottom, endBottom, progress).roundToInt()
                state.left = (xCenter - halfWidth).roundToInt()
                state.right = (xCenter + halfWidth).roundToInt()

                state.topCornerRadius = MathUtils.lerp(startTopCornerRadius, endRadius, progress)
                state.bottomCornerRadius =
                    MathUtils.lerp(startBottomCornerRadius, endRadius, progress)

                // The expanding view can/should be hidden once it is completely coverred by the
                // windowBackgroundLayer.
                state.visible =
                        getProgress(linearProgress, 0, ANIMATION_DURATION_FADE_OUT_CONTENT) < 1


                override fun onLaunchAnimationProgress(
                    state: LaunchAnimator.State,
                    progress: Float,
                    linearProgress: Float
                ) {
                    applyStateToWindow(window, state)
                    applyStateToWindow(window, state)
                applyStateToWindowBackgroundLayer(windowBackgroundLayer, state, linearProgress)
                    navigationBar?.let { applyStateToNavigationBar(it, state, linearProgress) }
                    navigationBar?.let { applyStateToNavigationBar(it, state, linearProgress) }

                    delegate.onLaunchAnimationProgress(state, progress, linearProgress)
                // If we started expanding the view, we make it 1 pixel smaller on all sides to
                // avoid artefacts on the corners caused by anti-aliasing of the view background and
                // the window background layer.
                if (state.top != startTop && state.left != startLeft &&
                        state.bottom != startBottom && state.right != startRight) {
                    state.top += 1
                    state.left += 1
                    state.right -= 1
                    state.bottom -= 1
                }
                }
                controller.onLaunchAnimationProgress(state, progress, linearProgress)
            }
            }


            animator.start()
            // We draw a hole when the additional layer is fading out to reveal the opening window.
            animation = launchAnimator.startAnimation(
                controller, endState, windowBackgroundColor, drawHole = true)
        }
        }


        private fun applyStateToWindow(window: RemoteAnimationTarget, state: State) {
        private fun applyStateToWindow(window: RemoteAnimationTarget, state: LaunchAnimator.State) {
            val screenBounds = window.screenSpaceBounds
            val screenBounds = window.screenSpaceBounds
            val centerX = (screenBounds.left + screenBounds.right) / 2f
            val centerX = (screenBounds.left + screenBounds.right) / 2f
            val centerY = (screenBounds.top + screenBounds.bottom) / 2f
            val centerY = (screenBounds.top + screenBounds.bottom) / 2f
@@ -632,48 +444,13 @@ class ActivityLaunchAnimator(
            transactionApplier.scheduleApply(params)
            transactionApplier.scheduleApply(params)
        }
        }


        private fun applyStateToWindowBackgroundLayer(
            drawable: GradientDrawable,
            state: State,
            linearProgress: Float
        ) {
            // Update position.
            drawable.setBounds(state.left, state.top, state.right, state.bottom)

            // Update radius.
            cornerRadii[0] = state.topCornerRadius
            cornerRadii[1] = state.topCornerRadius
            cornerRadii[2] = state.topCornerRadius
            cornerRadii[3] = state.topCornerRadius
            cornerRadii[4] = state.bottomCornerRadius
            cornerRadii[5] = state.bottomCornerRadius
            cornerRadii[6] = state.bottomCornerRadius
            cornerRadii[7] = state.bottomCornerRadius
            drawable.cornerRadii = cornerRadii

            // We first fade in the background layer to hide the expanding view, then fade it out
            // with SRC mode to draw a hole punch in the status bar and reveal the opening window.
            val fadeInProgress = getProgress(linearProgress, 0, ANIMATION_DURATION_FADE_OUT_CONTENT)
            if (fadeInProgress < 1) {
                val alpha = CONTENT_FADE_OUT_INTERPOLATOR.getInterpolation(fadeInProgress)
                drawable.alpha = (alpha * 0xFF).roundToInt()
                drawable.setXfermode(null)
            } else {
                val fadeOutProgress = getProgress(linearProgress,
                        ANIMATION_DELAY_FADE_IN_WINDOW, ANIMATION_DURATION_FADE_IN_WINDOW)
                val alpha = 1 - WINDOW_FADE_IN_INTERPOLATOR.getInterpolation(fadeOutProgress)
                drawable.alpha = (alpha * 0xFF).roundToInt()
                drawable.setXfermode(SRC_MODE)
            }
        }

        private fun applyStateToNavigationBar(
        private fun applyStateToNavigationBar(
            navigationBar: RemoteAnimationTarget,
            navigationBar: RemoteAnimationTarget,
            state: State,
            state: LaunchAnimator.State,
            linearProgress: Float
            linearProgress: Float
        ) {
        ) {
            val fadeInProgress = getProgress(linearProgress, ANIMATION_DELAY_NAV_FADE_IN,
            val fadeInProgress = LaunchAnimator.getProgress(linearProgress,
                    ANIMATION_DURATION_NAV_FADE_OUT)
                ANIMATION_DELAY_NAV_FADE_IN, ANIMATION_DURATION_NAV_FADE_OUT)


            val params = SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(navigationBar.leash)
            val params = SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(navigationBar.leash)
            if (fadeInProgress > 0) {
            if (fadeInProgress > 0) {
@@ -687,7 +464,7 @@ class ActivityLaunchAnimator(
                    .withWindowCrop(windowCrop)
                    .withWindowCrop(windowCrop)
                    .withVisibility(true)
                    .withVisibility(true)
            } else {
            } else {
                val fadeOutProgress = getProgress(linearProgress, 0,
                val fadeOutProgress = LaunchAnimator.getProgress(linearProgress, 0,
                    ANIMATION_DURATION_NAV_FADE_OUT)
                    ANIMATION_DURATION_NAV_FADE_OUT)
                params.withAlpha(1f - NAV_FADE_OUT_INTERPOLATOR.getInterpolation(fadeOutProgress))
                params.withAlpha(1f - NAV_FADE_OUT_INTERPOLATOR.getInterpolation(fadeOutProgress))
            }
            }
@@ -714,7 +491,7 @@ class ActivityLaunchAnimator(
            cancelled = true
            cancelled = true
            removeTimeout()
            removeTimeout()
            context.mainExecutor.execute {
            context.mainExecutor.execute {
                animator?.cancel()
                animation?.cancel()
                controller.onLaunchAnimationCancelled()
                controller.onLaunchAnimationCancelled()
            }
            }
        }
        }
@@ -726,9 +503,5 @@ class ActivityLaunchAnimator(
                e.printStackTrace()
                e.printStackTrace()
            }
            }
        }
        }

        private fun lerp(start: Int, stop: Int, amount: Float): Float {
            return MathUtils.lerp(start.toFloat(), stop.toFloat(), amount)
        }
    }
    }
}
}
+16 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2021 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.systemui.animation
package com.android.systemui.animation


/**
/**
Loading