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

Commit 98c83944 authored by Todd Lee's avatar Todd Lee
Browse files

Enable two-part fade out for splash screen reveal anim

ag/24465007 provided a FADE_OUT splash screen anim option
to replace the default 'reveal'.

This change enables the use of the existing configs supporting
a two-part fade where the icon/branding views and the splash
screen itself can be faded indepedently.

Take the following config from Wear for example:

<integer name="starting_window_app_reveal_icon_fade_out_duration">50</integer>
<integer name="starting_window_app_reveal_anim_delay">50</integer
<integer name="starting_window_app_reveal_anim_duration">200</integer>

This animation will fade out the icon (50 ms), at the same time waiting
to start the splash screen animation, which will then fade out over
200ms (total duration 250ms)

Note that the original fade out was implemented by TV - as such config
values have been put in place to make this change a no-op with respect
to that usage.

Bug: b/286280723
Test: manual validation of app launches with appropriate configs
Change-Id: I74b8b0b37538187f80d40c8561a98dac0f4eaffa
parent d9c84d54
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -44,6 +44,12 @@
    if a custom action is present before closing it. -->
    <integer name="config_pipForceCloseDelay">5000</integer>

    <!-- Animation duration when exit starting window: fade out icon -->
    <integer name="starting_window_app_reveal_icon_fade_out_duration">500</integer>

    <!-- Animation delay when exit starting window: reveal app -->
    <integer name="starting_window_app_reveal_anim_delay">0</integer>

    <!-- Animation duration when exit starting window: reveal app -->
    <integer name="starting_window_app_reveal_anim_duration">500</integer>

+35 −0
Original line number Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?>
<!--
  ~ Copyright (C) 2022 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.
  -->

<!-- These resources are around just to allow their values to be customized
     for watch products.  Do not translate. -->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">

    <!-- Animation duration when exit starting window: fade out icon -->
    <integer name="starting_window_app_reveal_icon_fade_out_duration">50</integer>

    <!-- Animation delay when exit starting window: reveal app -->
    <integer name="starting_window_app_reveal_anim_delay">50</integer>

    <!-- Animation duration when exit starting window: reveal app -->
    <integer name="starting_window_app_reveal_anim_duration">200</integer>

    <!-- Default animation type when hiding the starting window. The possible values are:
          - 0 for radial vanish + slide up
          - 1 for fade out -->
    <integer name="starting_window_exit_animation_type">1</integer>
</resources>
+5 −29
Original line number Diff line number Diff line
@@ -20,7 +20,6 @@ import static android.view.View.GONE;
import static com.android.internal.jank.InteractionJankMonitor.CUJ_SPLASHSCREEN_EXIT_ANIM;

import android.animation.Animator;
import android.annotation.IntDef;
import android.content.Context;
import android.graphics.Rect;
import android.util.Slog;
@@ -47,7 +46,7 @@ public class SplashScreenExitAnimation implements Animator.AnimatorListener {
    private final int mIconFadeOutDuration;
    private final int mAppRevealDelay;
    private final int mAppRevealDuration;
    @ExitAnimationType
    @SplashScreenExitAnimationUtils.ExitAnimationType
    private final int mAnimationType;
    private final int mAnimationDuration;
    private final float mIconStartAlpha;
@@ -58,24 +57,6 @@ public class SplashScreenExitAnimation implements Animator.AnimatorListener {

    private Runnable mFinishCallback;

    /**
    * This splash screen exit animation type uses a radial vanish to hide
    * the starting window and slides up the main window content.
    */
    private static final int TYPE_RADIAL_VANISH_SLIDE_UP = 0;

    /**
    * This splash screen exit animation type fades out the starting window
    * to reveal the main window content.
    */
    private static final int TYPE_FADE_OUT = 1;

    @IntDef(prefix = { "TYPE_" }, value = {
        TYPE_RADIAL_VANISH_SLIDE_UP,
        TYPE_FADE_OUT,
    })
    private @interface ExitAnimationType {}

    SplashScreenExitAnimation(Context context, SplashScreenView view, SurfaceControl leash,
            Rect frame, int mainWindowShiftLength, TransactionPool pool, Runnable handleFinish,
            float roundedCornerRadius) {
@@ -121,15 +102,10 @@ public class SplashScreenExitAnimation implements Animator.AnimatorListener {
    }

    void startAnimations() {
        if (mAnimationType == TYPE_FADE_OUT) {
            SplashScreenExitAnimationUtils.startFadeOutAnimation(mSplashScreenView,
                    mAnimationDuration, this);
        } else {
            SplashScreenExitAnimationUtils.startAnimations(mSplashScreenView, mFirstWindowSurface,
                    mMainWindowShiftLength, mTransactionPool, mFirstWindowFrame, mAnimationDuration,
                    mIconFadeOutDuration, mIconStartAlpha, mBrandingStartAlpha, mAppRevealDelay,
                    mAppRevealDuration, this, mRoundedCornerRadius);
        }
        SplashScreenExitAnimationUtils.startAnimations(mAnimationType, mSplashScreenView,
                mFirstWindowSurface, mMainWindowShiftLength, mTransactionPool, mFirstWindowFrame,
                mAnimationDuration, mIconFadeOutDuration, mIconStartAlpha, mBrandingStartAlpha,
                mAppRevealDelay, mAppRevealDuration, this, mRoundedCornerRadius);
    }

    private void reset() {
+89 −19
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import static android.view.Choreographer.CALLBACK_COMMIT;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.annotation.IntDef;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.Configuration;
@@ -54,6 +55,7 @@ import com.android.wm.shell.common.TransactionPool;
public class SplashScreenExitAnimationUtils {
    private static final boolean DEBUG_EXIT_ANIMATION = false;
    private static final boolean DEBUG_EXIT_ANIMATION_BLEND = false;
    private static final boolean DEBUG_EXIT_FADE_ANIMATION = false;
    private static final String TAG = "SplashScreenExitAnimationUtils";

    private static final Interpolator ICON_INTERPOLATOR = new PathInterpolator(0.15f, 0f, 1f, 1f);
@@ -61,20 +63,48 @@ public class SplashScreenExitAnimationUtils {
            new PathInterpolator(0f, 0f, 0.4f, 1f);
    private static final Interpolator SHIFT_UP_INTERPOLATOR = new PathInterpolator(0f, 0f, 0f, 1f);

    /**
     * This splash screen exit animation type uses a radial vanish to hide
     * the starting window and slides up the main window content.
     * @hide
     */
    public static final int TYPE_RADIAL_VANISH_SLIDE_UP = 0;

    /**
     * This splash screen exit animation type fades out the starting window
     * to reveal the main window content.
     * @hide
     */
    public static final int TYPE_FADE_OUT = 1;

    /** @hide */
    @IntDef(prefix = { "TYPE_" }, value = {
            TYPE_RADIAL_VANISH_SLIDE_UP,
            TYPE_FADE_OUT,
    })
    public @interface ExitAnimationType {}

    /**
     * Creates and starts the animator to fade out the icon, reveal the app, and shift up main
     * window with rounded corner radius.
     */
    static void startAnimations(ViewGroup splashScreenView,
            SurfaceControl firstWindowSurface, int mainWindowShiftLength,
            TransactionPool transactionPool, Rect firstWindowFrame, int animationDuration,
            int iconFadeOutDuration, float iconStartAlpha, float brandingStartAlpha,
            int appRevealDelay, int appRevealDuration, Animator.AnimatorListener animatorListener,
            float roundedCornerRadius) {
        ValueAnimator animator = createRadialVanishSlideUpAnimator(splashScreenView,
    static void startAnimations(@ExitAnimationType int animationType,
            ViewGroup splashScreenView, SurfaceControl firstWindowSurface,
            int mainWindowShiftLength, TransactionPool transactionPool, Rect firstWindowFrame,
            int animationDuration, int iconFadeOutDuration, float iconStartAlpha,
            float brandingStartAlpha, int appRevealDelay, int appRevealDuration,
            Animator.AnimatorListener animatorListener, float roundedCornerRadius) {
        ValueAnimator animator;
        if (animationType == TYPE_FADE_OUT) {
            animator = createFadeOutAnimation(splashScreenView, animationDuration,
                    iconFadeOutDuration, iconStartAlpha, brandingStartAlpha, appRevealDelay,
                    appRevealDuration, animatorListener);
        } else {
            animator = createRadialVanishSlideUpAnimator(splashScreenView,
                    firstWindowSurface, mainWindowShiftLength, transactionPool, firstWindowFrame,
                    animationDuration, iconFadeOutDuration, iconStartAlpha, brandingStartAlpha,
                    appRevealDelay, appRevealDuration, animatorListener, roundedCornerRadius);
        }
        animator.start();
    }

@@ -88,10 +118,11 @@ public class SplashScreenExitAnimationUtils {
            TransactionPool transactionPool, Rect firstWindowFrame, int animationDuration,
            int iconFadeOutDuration, float iconStartAlpha, float brandingStartAlpha,
            int appRevealDelay, int appRevealDuration, Animator.AnimatorListener animatorListener) {
        startAnimations(splashScreenView, firstWindowSurface, mainWindowShiftLength,
                transactionPool, firstWindowFrame, animationDuration, iconFadeOutDuration,
                iconStartAlpha, brandingStartAlpha, appRevealDelay, appRevealDuration,
                animatorListener, 0f /* roundedCornerRadius */);
        // Start the default 'reveal' animation.
        startAnimations(TYPE_RADIAL_VANISH_SLIDE_UP, splashScreenView,
                firstWindowSurface, mainWindowShiftLength, transactionPool, firstWindowFrame,
                animationDuration, iconFadeOutDuration, iconStartAlpha, brandingStartAlpha,
                appRevealDelay, appRevealDuration, animatorListener, 0f /* roundedCornerRadius */);
    }

    /**
@@ -209,18 +240,57 @@ public class SplashScreenExitAnimationUtils {
        return nightMode == Configuration.UI_MODE_NIGHT_YES;
    }

    static void startFadeOutAnimation(ViewGroup splashScreenView,
            int animationDuration, Animator.AnimatorListener animatorListener) {
        final ValueAnimator animator = ValueAnimator.ofFloat(1f, 0f);
    private static ValueAnimator createFadeOutAnimation(ViewGroup splashScreenView,
            int animationDuration, int iconFadeOutDuration, float iconStartAlpha,
            float brandingStartAlpha, int appRevealDelay, int appRevealDuration,
            Animator.AnimatorListener animatorListener) {

        if (DEBUG_EXIT_FADE_ANIMATION) {
            splashScreenView.setBackgroundColor(Color.BLUE);
        }

        final ValueAnimator animator = ValueAnimator.ofFloat(0f, 1f);
        animator.setDuration(animationDuration);
        animator.setInterpolator(Interpolators.LINEAR);
        animator.addUpdateListener(animation -> {
            splashScreenView.setAlpha((float) animation.getAnimatedValue());

            float linearProgress = (float) animation.getAnimatedValue();

            // Icon fade out progress (always starts immediately)
            final float iconFadeProgress = ICON_INTERPOLATOR.getInterpolation(getProgress(
                            linearProgress, 0 /* delay */, iconFadeOutDuration, animationDuration));
            View iconView = null;
            View brandingView = null;

            if (splashScreenView instanceof SplashScreenView) {
                iconView = ((SplashScreenView) splashScreenView).getIconView();
                brandingView = ((SplashScreenView) splashScreenView).getBrandingView();
            }
            if (iconView != null) {
                iconView.setAlpha(iconStartAlpha * (1f - iconFadeProgress));
            }
            if (brandingView != null) {
                brandingView.setAlpha(brandingStartAlpha * (1f - iconFadeProgress));
            }

            // Splash screen fade out progress (possibly delayed)
            final float splashFadeProgress = Interpolators.ALPHA_OUT.getInterpolation(
                    getProgress(linearProgress, appRevealDelay,
                    appRevealDuration, animationDuration));

            splashScreenView.setAlpha(1f - splashFadeProgress);

            if (DEBUG_EXIT_FADE_ANIMATION) {
                Slog.d(TAG, "progress -> animation: " + linearProgress
                        + "\t icon alpha: " + ((iconView != null) ? iconView.getAlpha() : "n/a")
                        + "\t splash alpha: " + splashScreenView.getAlpha()
                );
            }
        });
        if (animatorListener != null) {
            animator.addListener(animatorListener);
        }
        animator.start();
        return animator;
    }

    /**