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

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

Merge "Prevent SysUI from crashing during Ghost animation" into sc-dev

parents 2758f3c2 a39e6a27
Loading
Loading
Loading
Loading
+15 −5
Original line number Original line Diff line number Diff line
@@ -34,6 +34,8 @@ import com.android.wm.shell.startingsurface.SplashscreenContentDrawer
import com.android.wm.shell.startingsurface.StartingSurface
import com.android.wm.shell.startingsurface.StartingSurface
import kotlin.math.roundToInt
import kotlin.math.roundToInt


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.
@@ -43,8 +45,6 @@ class ActivityLaunchAnimator(
    private val startingSurface: StartingSurface?,
    private val startingSurface: StartingSurface?,
    context: Context
    context: Context
) {
) {
    private val TAG = this::class.java.simpleName

    companion object {
    companion object {
        const val ANIMATION_DURATION = 500L
        const val ANIMATION_DURATION = 500L
        private const val ANIMATION_DURATION_FADE_OUT_CONTENT = 150L
        private const val ANIMATION_DURATION_FADE_OUT_CONTENT = 150L
@@ -233,11 +233,21 @@ class ActivityLaunchAnimator(
            /**
            /**
             * 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.
             *
             *
             * Important: The view must be attached to the window when calling this function and
             * Important: The view must be attached to a [ViewGroup] when calling this function and
             * during the animation.
             * during the animation. For safety, this method will return null when it is not.
             */
             */
            @JvmStatic
            @JvmStatic
            fun fromView(view: View, cujType: Int? = null): Controller {
            fun fromView(view: View, cujType: Int? = null): Controller? {
                if (view.parent !is ViewGroup) {
                    // TODO(b/192194319): Throw instead of just logging.
                    Log.wtf(
                        TAG,
                        "Skipping animation as view $view is not attached to a ViewGroup",
                        Exception()
                    )
                    return null
                }

                return GhostedViewLaunchAnimatorController(view, cujType)
                return GhostedViewLaunchAnimatorController(view, cujType)
            }
            }
        }
        }
+18 −3
Original line number Original line Diff line number Diff line
@@ -9,6 +9,7 @@ import android.graphics.drawable.Drawable
import android.graphics.drawable.GradientDrawable
import android.graphics.drawable.GradientDrawable
import android.graphics.drawable.InsetDrawable
import android.graphics.drawable.InsetDrawable
import android.graphics.drawable.LayerDrawable
import android.graphics.drawable.LayerDrawable
import android.util.Log
import android.view.GhostView
import android.view.GhostView
import android.view.View
import android.view.View
import android.view.ViewGroup
import android.view.ViewGroup
@@ -17,13 +18,15 @@ import android.widget.FrameLayout
import com.android.internal.jank.InteractionJankMonitor
import com.android.internal.jank.InteractionJankMonitor
import kotlin.math.min
import kotlin.math.min


private const val TAG = "GhostedViewLaunchAnimatorController"

/**
/**
 * A base implementation of [ActivityLaunchAnimator.Controller] which creates a [ghost][GhostView]
 * A base implementation of [ActivityLaunchAnimator.Controller] which creates a [ghost][GhostView]
 * of [ghostedView] as well as an expandable background view, which are drawn and animated instead
 * of [ghostedView] as well as an expandable background view, which are drawn and animated instead
 * of the ghosted view.
 * of the ghosted view.
 *
 *
 * Important: [ghostedView] must be attached to the window when calling this function and during the
 * Important: [ghostedView] must be attached to a [ViewGroup] when calling this function and during
 * animation.
 * the animation.
 *
 *
 * Note: Avoid instantiating this directly and call [ActivityLaunchAnimator.Controller.fromView]
 * Note: Avoid instantiating this directly and call [ActivityLaunchAnimator.Controller.fromView]
 * whenever possible instead.
 * whenever possible instead.
@@ -113,6 +116,13 @@ open class GhostedViewLaunchAnimatorController(
    }
    }


    override fun onLaunchAnimationStart(isExpandingFullyAbove: Boolean) {
    override fun onLaunchAnimationStart(isExpandingFullyAbove: Boolean) {
        if (ghostedView.parent !is ViewGroup) {
            // This should usually not happen, but let's make sure we don't crash if the view was
            // detached right before we started the animation.
            Log.w(TAG, "Skipping animation as ghostedView is not attached to a ViewGroup")
            return
        }

        backgroundView = FrameLayout(launchContainer.context)
        backgroundView = FrameLayout(launchContainer.context)
        launchContainerOverlay.add(backgroundView)
        launchContainerOverlay.add(backgroundView)


@@ -138,7 +148,7 @@ open class GhostedViewLaunchAnimatorController(
        progress: Float,
        progress: Float,
        linearProgress: Float
        linearProgress: Float
    ) {
    ) {
        val ghostView = this.ghostView!!
        val ghostView = this.ghostView ?: return
        val backgroundView = this.backgroundView!!
        val backgroundView = this.backgroundView!!


        if (!state.visible) {
        if (!state.visible) {
@@ -173,6 +183,11 @@ open class GhostedViewLaunchAnimatorController(
    }
    }


    override fun onLaunchAnimationEnd(isExpandingFullyAbove: Boolean) {
    override fun onLaunchAnimationEnd(isExpandingFullyAbove: Boolean) {
        if (ghostView == null) {
            // We didn't actually run the animation.
            return
        }

        cujType?.let { InteractionJankMonitor.getInstance().end(it) }
        cujType?.let { InteractionJankMonitor.getInstance().end(it) }


        backgroundDrawable?.wrapped?.alpha = startBackgroundAlpha
        backgroundDrawable?.wrapped?.alpha = startBackgroundAlpha
+7 −0
Original line number Original line Diff line number Diff line
@@ -475,6 +475,13 @@ public class MediaControlPanel {
    @Nullable
    @Nullable
    private ActivityLaunchAnimator.Controller buildLaunchAnimatorController(
    private ActivityLaunchAnimator.Controller buildLaunchAnimatorController(
            TransitionLayout player) {
            TransitionLayout player) {
        if (!(player.getParent() instanceof ViewGroup)) {
            // TODO(b/192194319): Throw instead of just logging.
            Log.wtf(TAG, "Skipping player animation as it is not attached to a ViewGroup",
                    new Exception());
            return null;
        }

        // TODO(b/174236650): Make sure that the carousel indicator also fades out.
        // TODO(b/174236650): Make sure that the carousel indicator also fades out.
        // TODO(b/174236650): Instrument the animation to measure jank.
        // TODO(b/174236650): Instrument the animation to measure jank.
        return new GhostedViewLaunchAnimatorController(player,
        return new GhostedViewLaunchAnimatorController(player,
+2 −1
Original line number Original line Diff line number Diff line
@@ -514,7 +514,8 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
                                    InteractionJankMonitor.CUJ_SHADE_APP_LAUNCH_FROM_HISTORY_BUTTON
                                    InteractionJankMonitor.CUJ_SHADE_APP_LAUNCH_FROM_HISTORY_BUTTON
                            );
                            );
                    ActivityLaunchAnimator.Controller animationController =
                    ActivityLaunchAnimator.Controller animationController =
                            new StatusBarLaunchAnimatorController(viewController, mStatusBar,
                            viewController == null ? null
                                : new StatusBarLaunchAnimatorController(viewController, mStatusBar,
                                    true /* isActivityIntent */);
                                    true /* isActivityIntent */);


                    mActivityLaunchAnimator.startIntentWithAnimation(animationController, animate,
                    mActivityLaunchAnimator.startIntentWithAnimation(animationController, animate,
+6 −0
Original line number Original line Diff line number Diff line
@@ -14,6 +14,7 @@ import android.view.IRemoteAnimationFinishedCallback
import android.view.RemoteAnimationAdapter
import android.view.RemoteAnimationAdapter
import android.view.RemoteAnimationTarget
import android.view.RemoteAnimationTarget
import android.view.SurfaceControl
import android.view.SurfaceControl
import android.view.View
import android.view.ViewGroup
import android.view.ViewGroup
import android.widget.LinearLayout
import android.widget.LinearLayout
import androidx.test.filters.SmallTest
import androidx.test.filters.SmallTest
@@ -177,6 +178,11 @@ class ActivityLaunchAnimatorTest : SysuiTestCase() {
        verify(controller).onLaunchAnimationStart(anyBoolean())
        verify(controller).onLaunchAnimationStart(anyBoolean())
    }
    }


    @Test
    fun controllerFromOrphanViewReturnsNull() {
        assertNull(ActivityLaunchAnimator.Controller.fromView(View(mContext)))
    }

    private fun fakeWindow(): RemoteAnimationTarget {
    private fun fakeWindow(): RemoteAnimationTarget {
        val bounds = Rect(10 /* left */, 20 /* top */, 30 /* right */, 40 /* bottom */)
        val bounds = Rect(10 /* left */, 20 /* top */, 30 /* right */, 40 /* bottom */)
        val taskInfo = ActivityManager.RunningTaskInfo()
        val taskInfo = ActivityManager.RunningTaskInfo()
Loading