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

Commit eb6c71b9 authored by Jordan Demeulenaere's avatar Jordan Demeulenaere Committed by Android (Google) Code Review
Browse files

Merge changes I49c6095f,Id14bee4b into tm-qpr-dev

* changes:
  Support Activity launches above the expandable
  Format Kotlin code in SysUI Animation lib using ktfmt
parents e8bbc028 7bb86722
Loading
Loading
Loading
Loading
+182 −122
Original line number Diff line number Diff line
@@ -59,7 +59,8 @@ class ActivityLaunchAnimator(
    companion object {
        /** The timings when animating a View into an app. */
        @JvmField
        val TIMINGS = LaunchAnimator.Timings(
        val TIMINGS =
            LaunchAnimator.Timings(
                totalDuration = 500L,
                contentBeforeFadeOutDelay = 0L,
                contentBeforeFadeOutDuration = 150L,
@@ -72,13 +73,12 @@ class ActivityLaunchAnimator(
         * showing the app (which is under the dialog window) so that the dialog window dim is fully
         * faded out, to avoid flicker.
         */
        val DIALOG_TIMINGS = TIMINGS.copy(
            contentBeforeFadeOutDuration = 200L,
            contentAfterFadeInDelay = 200L
        )
        val DIALOG_TIMINGS =
            TIMINGS.copy(contentBeforeFadeOutDuration = 200L, contentAfterFadeInDelay = 200L)

        /** The interpolators when animating a View or a dialog into an app. */
        val INTERPOLATORS = LaunchAnimator.Interpolators(
        val INTERPOLATORS =
            LaunchAnimator.Interpolators(
                positionInterpolator = Interpolators.EMPHASIZED,
                positionXInterpolator = createPositionXInterpolator(),
                contentBeforeFadeOutInterpolator = Interpolators.LINEAR_OUT_SLOW_IN,
@@ -98,7 +98,8 @@ class ActivityLaunchAnimator(
        private const val LAUNCH_TIMEOUT = 1000L

        private fun createPositionXInterpolator(): Interpolator {
            val path = Path().apply {
            val path =
                Path().apply {
                    moveTo(0f, 0f)
                    cubicTo(0.1217f, 0.0462f, 0.15f, 0.4686f, 0.1667f, 0.66f)
                    cubicTo(0.1834f, 0.8878f, 0.1667f, 1f, 1f, 1f)
@@ -150,14 +151,18 @@ class ActivityLaunchAnimator(
            return
        }

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

        // Pass the RemoteAnimationAdapter to the intent starter only if we are not hiding the
        // keyguard with the animation
        val animationAdapter = if (!hideKeyguardWithAnimation) {
        val animationAdapter =
            if (!hideKeyguardWithAnimation) {
                RemoteAnimationAdapter(
                    runner,
                    TIMINGS.totalDuration,
@@ -171,8 +176,12 @@ class ActivityLaunchAnimator(
        // activity launches.
        if (packageName != null && animationAdapter != null) {
            try {
                ActivityTaskManager.getService().registerRemoteAnimationForNextActivityStart(
                    packageName, animationAdapter, null /* launchCookie */)
                ActivityTaskManager.getService()
                    .registerRemoteAnimationForNextActivityStart(
                        packageName,
                        animationAdapter,
                        null /* launchCookie */
                    )
            } catch (e: RemoteException) {
                Log.w(TAG, "Unable to register the remote animation", e)
            }
@@ -188,8 +197,11 @@ class ActivityLaunchAnimator(
                (launchResult == ActivityManager.START_DELIVERED_TO_TOP &&
                    hideKeyguardWithAnimation)

        Log.i(TAG, "launchResult=$launchResult willAnimate=$willAnimate " +
                "hideKeyguardWithAnimation=$hideKeyguardWithAnimation")
        Log.i(
            TAG,
            "launchResult=$launchResult willAnimate=$willAnimate " +
                "hideKeyguardWithAnimation=$hideKeyguardWithAnimation"
        )
        controller.callOnIntentStartedOnMainThread(willAnimate)

        // If we expect an animation, post a timeout to cancel it in case the remote animation is
@@ -206,9 +218,7 @@ class ActivityLaunchAnimator(

    private fun Controller.callOnIntentStartedOnMainThread(willAnimate: Boolean) {
        if (Looper.myLooper() != Looper.getMainLooper()) {
            this.launchContainer.context.mainExecutor.execute {
                this.onIntentStarted(willAnimate)
            }
            this.launchContainer.context.mainExecutor.execute { this.onIntentStarted(willAnimate) }
        } else {
            this.onIntentStarted(willAnimate)
        }
@@ -246,8 +256,7 @@ class ActivityLaunchAnimator(
    }

    /** Create a new animation [Runner] controlled by [controller]. */
    @VisibleForTesting
    fun createRunner(controller: Controller): Runner = Runner(controller)
    @VisibleForTesting fun createRunner(controller: Controller): Runner = Runner(controller)

    interface PendingIntentStarter {
        /**
@@ -271,19 +280,16 @@ class ActivityLaunchAnimator(

    interface Listener {
        /** Called when an activity launch animation started. */
        @JvmDefault
        fun onLaunchAnimationStart() {}
        @JvmDefault fun onLaunchAnimationStart() {}

        /**
         * Called when an activity launch animation is finished. This will be called if and only if
         * [onLaunchAnimationStart] was called earlier.
         */
        @JvmDefault
        fun onLaunchAnimationEnd() {}
        @JvmDefault fun onLaunchAnimationEnd() {}

        /** Called when an activity launch animation made progress. */
        @JvmDefault
        fun onLaunchAnimationProgress(linearProgress: Float) {}
        @JvmDefault fun onLaunchAnimationProgress(linearProgress: Float) {}
    }

    /**
@@ -326,6 +332,17 @@ class ActivityLaunchAnimator(
        val isDialogLaunch: Boolean
            get() = false

        /**
         * Whether the expandable controller by this [Controller] is below the launching window that
         * is going to be animated.
         *
         * This should be `false` when launching an app from the shade or status bar, given that
         * they are drawn above all apps. This is usually `true` when using this launcher in a
         * normal app or a launcher, that are drawn below the animating activity/window.
         */
        val isBelowAnimatingWindow: Boolean
            get() = false

        /**
         * The intent was started. If [willAnimate] is false, nothing else will happen and the
         * animation will not be started.
@@ -394,9 +411,7 @@ class ActivityLaunchAnimator(
                return
            }

            context.mainExecutor.execute {
                startAnimation(apps, nonApps, iCallback)
            }
            context.mainExecutor.execute { startAnimation(apps, nonApps, iCallback) }
        }

        private fun startAnimation(
@@ -408,9 +423,7 @@ class ActivityLaunchAnimator(
                Log.d(TAG, "Remote animation started")
            }

            val window = apps?.firstOrNull {
                it.mode == RemoteAnimationTarget.MODE_OPENING
            }
            val window = apps?.firstOrNull { it.mode == RemoteAnimationTarget.MODE_OPENING }

            if (window == null) {
                Log.i(TAG, "Aborting the animation as no window is opening")
@@ -420,23 +433,26 @@ class ActivityLaunchAnimator(
                return
            }

            val navigationBar = nonApps?.firstOrNull {
            val navigationBar =
                nonApps?.firstOrNull {
                    it.windowType == WindowManager.LayoutParams.TYPE_NAVIGATION_BAR
                }

            val windowBounds = window.screenSpaceBounds
            val endState = LaunchAnimator.State(
            val endState =
                LaunchAnimator.State(
                    top = windowBounds.top,
                    bottom = windowBounds.bottom,
                    left = windowBounds.left,
                    right = windowBounds.right
                )
            val callback = this@ActivityLaunchAnimator.callback!!
            val windowBackgroundColor = window.taskInfo?.let { callback.getBackgroundColor(it) }
                    ?: window.backgroundColor
            val windowBackgroundColor =
                window.taskInfo?.let { callback.getBackgroundColor(it) } ?: window.backgroundColor

            // Make sure we use the modified timings when animating a dialog into an app.
            val launchAnimator = if (controller.isDialogLaunch) {
            val launchAnimator =
                if (controller.isDialogLaunch) {
                    dialogToAppAnimator
                } else {
                    launchAnimator
@@ -446,12 +462,14 @@ class ActivityLaunchAnimator(
            // instead of recomputing isExpandingFullyAbove here.
            val isExpandingFullyAbove =
                launchAnimator.isExpandingFullyAbove(controller.launchContainer, endState)
            val endRadius = if (isExpandingFullyAbove) {
            val endRadius =
                if (isExpandingFullyAbove) {
                    // Most of the time, expanding fully above the root view means expanding in full
                    // screen.
                    ScreenDecorationsUtils.getWindowCornerRadius(context)
                } else {
                // This usually means we are in split screen mode, so 2 out of 4 corners will have
                    // This usually means we are in split screen mode, so 2 out of 4 corners will
                    // have
                    // a radius of 0.
                    0f
                }
@@ -460,7 +478,8 @@ class ActivityLaunchAnimator(

            // We animate the opening window and delegate the view expansion to [this.controller].
            val delegate = this.controller
            val controller = object : LaunchAnimator.Controller by delegate {
            val controller =
                object : Controller by delegate {
                    override fun onLaunchAnimationStart(isExpandingFullyAbove: Boolean) {
                        listeners.forEach { it.onLaunchAnimationStart() }
                        delegate.onLaunchAnimationStart(isExpandingFullyAbove)
@@ -477,10 +496,10 @@ class ActivityLaunchAnimator(
                        progress: Float,
                        linearProgress: Float
                    ) {
                    // Apply the state to the window only if it is visible, i.e. when the expanding
                    // view is *not* visible.
                        // Apply the state to the window only if it is visible, i.e. when the
                        // expanding view is *not* visible.
                        if (!state.visible) {
                        applyStateToWindow(window, state)
                            applyStateToWindow(window, state, linearProgress)
                        }
                        navigationBar?.let { applyStateToNavigationBar(it, state, linearProgress) }

@@ -489,11 +508,21 @@ class ActivityLaunchAnimator(
                    }
                }

            animation = launchAnimator.startAnimation(
                controller, endState, windowBackgroundColor, drawHole = true)
            animation =
                launchAnimator.startAnimation(
                    controller,
                    endState,
                    windowBackgroundColor,
                    fadeOutWindowBackgroundLayer = !controller.isBelowAnimatingWindow,
                    drawHole = !controller.isBelowAnimatingWindow,
                )
        }

        private fun applyStateToWindow(window: RemoteAnimationTarget, state: LaunchAnimator.State) {
        private fun applyStateToWindow(
            window: RemoteAnimationTarget,
            state: LaunchAnimator.State,
            linearProgress: Float,
        ) {
            if (transactionApplierView.viewRootImpl == null) {
                // If the view root we synchronize with was detached, don't apply any transaction
                // (as [SyncRtSurfaceTransactionApplier.scheduleApply] would otherwise throw).
@@ -535,14 +564,33 @@ class ActivityLaunchAnimator(
                windowCropF.bottom.roundToInt()
            )

            // The alpha of the opening window. If it opens above the expandable, then it should
            // fade in progressively. Otherwise, it should be fully opaque and will be progressively
            // revealed as the window background color layer above the window fades out.
            val alpha =
                if (controller.isBelowAnimatingWindow) {
                    val windowProgress =
                        LaunchAnimator.getProgress(
                            TIMINGS,
                            linearProgress,
                            TIMINGS.contentAfterFadeInDelay,
                            TIMINGS.contentAfterFadeInDuration
                        )

                    INTERPOLATORS.contentAfterFadeInInterpolator.getInterpolation(windowProgress)
                } else {
                    1f
                }

            // The scale will also be applied to the corner radius, so we divide by the scale to
            // keep the original radius. We use the max of (topCornerRadius, bottomCornerRadius) to
            // make sure that the window does not draw itself behind the expanding view. This is
            // especially important for lock screen animations, where the window is not clipped by
            // the shade.
            val cornerRadius = maxOf(state.topCornerRadius, state.bottomCornerRadius) / scale
            val params = SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(window.leash)
                .withAlpha(1f)
            val params =
                SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(window.leash)
                    .withAlpha(alpha)
                    .withMatrix(matrix)
                    .withWindowCrop(windowCrop)
                    .withCornerRadius(cornerRadius)
@@ -563,14 +611,21 @@ class ActivityLaunchAnimator(
                return
            }

            val fadeInProgress = LaunchAnimator.getProgress(TIMINGS, linearProgress,
                ANIMATION_DELAY_NAV_FADE_IN, ANIMATION_DURATION_NAV_FADE_OUT)
            val fadeInProgress =
                LaunchAnimator.getProgress(
                    TIMINGS,
                    linearProgress,
                    ANIMATION_DELAY_NAV_FADE_IN,
                    ANIMATION_DURATION_NAV_FADE_OUT
                )

            val params = SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(navigationBar.leash)
            if (fadeInProgress > 0) {
                matrix.reset()
                matrix.setTranslate(
                    0f, (state.top - navigationBar.sourceContainerBounds.top).toFloat())
                    0f,
                    (state.top - navigationBar.sourceContainerBounds.top).toFloat()
                )
                windowCrop.set(state.left, 0, state.right, state.height)
                params
                    .withAlpha(NAV_FADE_IN_INTERPOLATOR.getInterpolation(fadeInProgress))
@@ -578,8 +633,13 @@ class ActivityLaunchAnimator(
                    .withWindowCrop(windowCrop)
                    .withVisibility(true)
            } else {
                val fadeOutProgress = LaunchAnimator.getProgress(TIMINGS, linearProgress, 0,
                    ANIMATION_DURATION_NAV_FADE_OUT)
                val fadeOutProgress =
                    LaunchAnimator.getProgress(
                        TIMINGS,
                        linearProgress,
                        0,
                        ANIMATION_DURATION_NAV_FADE_OUT
                    )
                params.withAlpha(1f - NAV_FADE_OUT_INTERPOLATOR.getInterpolation(fadeOutProgress))
            }

+265 −230

File changed.

Preview size limit exceeded, changes collapsed.

+10 −10
Original line number Diff line number Diff line
@@ -105,9 +105,7 @@ open class GhostedViewLaunchAnimatorController(
            }

            // Perform a BFS to find the largest View with background.
            val views = LinkedList<View>().apply {
                add(view)
            }
            val views = LinkedList<View>().apply { add(view) }

            while (views.isNotEmpty()) {
                val v = views.removeFirst()
@@ -161,7 +159,8 @@ open class GhostedViewLaunchAnimatorController(
    }

    override fun createAnimatorState(): LaunchAnimator.State {
        val state = LaunchAnimator.State(
        val state =
            LaunchAnimator.State(
                topCornerRadius = getCurrentTopCornerRadius(),
                bottomCornerRadius = getCurrentBottomCornerRadius()
            )
@@ -255,7 +254,8 @@ open class GhostedViewLaunchAnimatorController(

        launchContainer.getLocationOnScreen(launchContainerLocation)
        ghostViewMatrix.postScale(
            scale, scale,
            scale,
            scale,
            ghostedViewState.centerX - launchContainerLocation[0],
            ghostedViewState.centerY - launchContainerLocation[1]
        )
+81 −67
Original line number Diff line number Diff line
@@ -34,10 +34,7 @@ import kotlin.math.roundToInt
private const val TAG = "LaunchAnimator"

/** A base class to animate a window launch (activity or dialog) from a view . */
class LaunchAnimator(
    private val timings: Timings,
    private val interpolators: Interpolators
) {
class LaunchAnimator(private val timings: Timings, private val interpolators: Interpolators) {
    companion object {
        internal const val DEBUG = false
        private val SRC_MODE = PorterDuffXfermode(PorterDuff.Mode.SRC)
@@ -77,8 +74,8 @@ class LaunchAnimator(
         * This will be used to:
         * - Get the associated [Context].
         * - Compute whether we are expanding fully above the launch container.
         *  - Get to overlay to which we initially put the window background layer, until the
         *    opening window is made visible (see [openingWindowSyncView]).
         * - Get to overlay to which we initially put the window background layer, until the opening
         * window is made visible (see [openingWindowSyncView]).
         *
         * 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
@@ -132,7 +129,6 @@ class LaunchAnimator(
        var bottom: Int = 0,
        var left: Int = 0,
        var right: Int = 0,

        var topCornerRadius: Float = 0f,
        var bottomCornerRadius: Float = 0f
    ) {
@@ -202,18 +198,20 @@ class LaunchAnimator(
    )

    /**
     * Start a launch animation controlled by [controller] towards [endState]. An intermediary
     * layer with [windowBackgroundColor] will fade in then fade out above the expanding view, and
     * should be the same background color as the opening (or closing) window. If [drawHole] is
     * true, then this intermediary layer will be drawn with SRC blending mode while it fades out.
     * Start a launch animation controlled by [controller] towards [endState]. An intermediary layer
     * with [windowBackgroundColor] will fade in then (optionally) fade out above the expanding
     * view, and should be the same background color as the opening (or closing) window.
     *
     * TODO(b/184121838): Remove [drawHole] and instead make the StatusBar draw this hole instead.
     * If [fadeOutWindowBackgroundLayer] is true, then this intermediary layer will fade out during
     * the second half of the animation, and will have SRC blending mode (ultimately punching a hole
     * in the [launch container][Controller.launchContainer]) iff [drawHole] is true.
     */
    fun startAnimation(
        controller: Controller,
        endState: State,
        windowBackgroundColor: Int,
        drawHole: Boolean = false
        fadeOutWindowBackgroundLayer: Boolean = true,
        drawHole: Boolean = false,
    ): Animation {
        val state = controller.createAnimatorState()

@@ -238,8 +236,12 @@ class LaunchAnimator(
        val endBottomCornerRadius = endState.bottomCornerRadius

        fun maybeUpdateEndState() {
            if (endTop != endState.top || endBottom != endState.bottom ||
                endLeft != endState.left || endRight != endState.right) {
            if (
                endTop != endState.top ||
                    endBottom != endState.bottom ||
                    endLeft != endState.left ||
                    endRight != endState.right
            ) {
                endTop = endState.top
                endBottom = endState.bottom
                endLeft = endState.left
@@ -256,7 +258,8 @@ class LaunchAnimator(
        // color, which is usually the same color of the app background. We first fade in this layer
        // to hide the expanding view, then we fade it out with SRC mode to draw a hole in the
        // launch container and reveal the opening window.
        val windowBackgroundLayer = GradientDrawable().apply {
        val windowBackgroundLayer =
            GradientDrawable().apply {
                setColor(windowBackgroundColor)
                alpha = 0
            }
@@ -270,14 +273,16 @@ class LaunchAnimator(
        // [Controller.openingWindowSyncView] once the opening app window starts to be visible.
        val openingWindowSyncView = controller.openingWindowSyncView
        val openingWindowSyncViewOverlay = openingWindowSyncView?.overlay
        val moveBackgroundLayerWhenAppIsVisible = openingWindowSyncView != null &&
        val moveBackgroundLayerWhenAppIsVisible =
            openingWindowSyncView != null &&
                openingWindowSyncView.viewRootImpl != controller.launchContainer.viewRootImpl

        val launchContainerOverlay = launchContainer.overlay
        var cancelled = false
        var movedBackgroundLayer = false

        animator.addListener(object : AnimatorListenerAdapter() {
        animator.addListener(
            object : AnimatorListenerAdapter() {
                override fun onAnimationStart(animation: Animator?, isReverse: Boolean) {
                    if (DEBUG) {
                        Log.d(TAG, "Animation started")
@@ -301,7 +306,8 @@ class LaunchAnimator(
                        openingWindowSyncViewOverlay?.remove(windowBackgroundLayer)
                    }
                }
        })
            }
        )

        animator.addUpdateListener { animation ->
            if (cancelled) {
@@ -333,7 +339,8 @@ class LaunchAnimator(

            // The expanding view can/should be hidden once it is completely covered by the opening
            // window.
            state.visible = getProgress(
            state.visible =
                getProgress(
                    timings,
                    linearProgress,
                    timings.contentBeforeFadeOutDelay,
@@ -352,7 +359,8 @@ class LaunchAnimator(
                ViewRootSync.synchronizeNextDraw(launchContainer, openingWindowSyncView, then = {})
            }

            val container = if (movedBackgroundLayer) {
            val container =
                if (movedBackgroundLayer) {
                    openingWindowSyncView!!
                } else {
                    controller.launchContainer
@@ -363,6 +371,7 @@ class LaunchAnimator(
                state,
                linearProgress,
                container,
                fadeOutWindowBackgroundLayer,
                drawHole
            )
            controller.onLaunchAnimationProgress(state, progress, linearProgress)
@@ -391,6 +400,7 @@ class LaunchAnimator(
        state: State,
        linearProgress: Float,
        launchContainer: View,
        fadeOutWindowBackgroundLayer: Boolean,
        drawHole: Boolean
    ) {
        // Update position.
@@ -415,7 +425,8 @@ class LaunchAnimator(

        // 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(
        val fadeInProgress =
            getProgress(
                timings,
                linearProgress,
                timings.contentBeforeFadeOutDelay,
@@ -425,8 +436,9 @@ class LaunchAnimator(
            val alpha =
                interpolators.contentBeforeFadeOutInterpolator.getInterpolation(fadeInProgress)
            drawable.alpha = (alpha * 0xFF).roundToInt()
        } else {
            val fadeOutProgress = getProgress(
        } else if (fadeOutWindowBackgroundLayer) {
            val fadeOutProgress =
                getProgress(
                    timings,
                    linearProgress,
                    timings.contentAfterFadeInDelay,
@@ -439,6 +451,8 @@ class LaunchAnimator(
            if (drawHole) {
                drawable.setXfermode(SRC_MODE)
            }
        } else {
            drawable.alpha = 0xFF
        }
    }
}
+111 −76

File changed.

Preview size limit exceeded, changes collapsed.

Loading