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

Commit 6e6533df authored by Jordan Demeulenaere's avatar Jordan Demeulenaere Committed by Automerger Merge Worker
Browse files

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

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/15235792

Change-Id: Ia1893294c742d3c26466c2ae7de654410850a89e
parents 1dfe1ebe e388c262
Loading
Loading
Loading
Loading
+15 −5
Original line number Diff line number Diff line
@@ -34,6 +34,8 @@ import com.android.wm.shell.startingsurface.SplashscreenContentDrawer
import com.android.wm.shell.startingsurface.StartingSurface
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
 * nicely into the starting window.
@@ -43,8 +45,6 @@ class ActivityLaunchAnimator(
    private val startingSurface: StartingSurface?,
    context: Context
) {
    private val TAG = this::class.java.simpleName

    companion object {
        const val ANIMATION_DURATION = 500L
        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.
             *
             * Important: The view must be attached to the window when calling this function and
             * during the animation.
             * Important: The view must be attached to a [ViewGroup] when calling this function and
             * during the animation. For safety, this method will return null when it is not.
             */
            @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)
            }
        }
+18 −3
Original line number Diff line number Diff line
@@ -9,6 +9,7 @@ import android.graphics.drawable.Drawable
import android.graphics.drawable.GradientDrawable
import android.graphics.drawable.InsetDrawable
import android.graphics.drawable.LayerDrawable
import android.util.Log
import android.view.GhostView
import android.view.View
import android.view.ViewGroup
@@ -17,13 +18,15 @@ import android.widget.FrameLayout
import com.android.internal.jank.InteractionJankMonitor
import kotlin.math.min

private const val TAG = "GhostedViewLaunchAnimatorController"

/**
 * 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 the ghosted view.
 *
 * Important: [ghostedView] must be attached to the window when calling this function and during the
 * animation.
 * Important: [ghostedView] must be attached to a [ViewGroup] when calling this function and during
 * the animation.
 *
 * Note: Avoid instantiating this directly and call [ActivityLaunchAnimator.Controller.fromView]
 * whenever possible instead.
@@ -113,6 +116,13 @@ open class GhostedViewLaunchAnimatorController(
    }

    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)
        launchContainerOverlay.add(backgroundView)

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

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

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

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

        backgroundDrawable?.wrapped?.alpha = startBackgroundAlpha
+7 −0
Original line number Diff line number Diff line
@@ -475,6 +475,13 @@ public class MediaControlPanel {
    @Nullable
    private ActivityLaunchAnimator.Controller buildLaunchAnimatorController(
            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): Instrument the animation to measure jank.
        return new GhostedViewLaunchAnimatorController(player,
+2 −1
Original line number Diff line number Diff line
@@ -514,7 +514,8 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
                                    InteractionJankMonitor.CUJ_SHADE_APP_LAUNCH_FROM_HISTORY_BUTTON
                            );
                    ActivityLaunchAnimator.Controller animationController =
                            new StatusBarLaunchAnimatorController(viewController, mStatusBar,
                            viewController == null ? null
                                : new StatusBarLaunchAnimatorController(viewController, mStatusBar,
                                    true /* isActivityIntent */);

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

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

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