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

Commit 5719f05c authored by Wei Sheng Shih's avatar Wei Sheng Shih Committed by Android (Google) Code Review
Browse files

Merge "Refine splash screen APIs" into sc-dev

parents b1f4cb5b 8ab6b928
Loading
Loading
Loading
Loading
+6 −5
Original line number Diff line number Diff line
@@ -56741,18 +56741,19 @@ package android.widget.inline {
package android.window {
  public interface SplashScreen {
    method public void setOnExitAnimationListener(@Nullable android.window.SplashScreen.OnExitAnimationListener);
    method public void clearOnExitAnimationListener();
    method public void setOnExitAnimationListener(@NonNull android.window.SplashScreen.OnExitAnimationListener);
  }
  public static interface SplashScreen.OnExitAnimationListener {
    method public void onSplashScreenExit(@NonNull android.window.SplashScreenView);
    method @UiThread public void onSplashScreenExit(@NonNull android.window.SplashScreenView);
  }
  public final class SplashScreenView extends android.widget.FrameLayout {
    method public long getIconAnimationDurationMillis();
    method public long getIconAnimationStartMillis();
    method @Nullable public java.time.Duration getIconAnimationDuration();
    method @Nullable public java.time.Instant getIconAnimationStart();
    method @Nullable public android.view.View getIconView();
    method public void remove();
    method @UiThread public void remove();
  }
}
+26 −11
Original line number Diff line number Diff line
@@ -17,8 +17,8 @@
package android.window;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.annotation.UiThread;
import android.app.Activity;
import android.app.ActivityThread;
import android.content.Context;
@@ -52,7 +52,13 @@ public interface SplashScreen {
     * @see OnExitAnimationListener#onSplashScreenExit(SplashScreenView)
     */
    @SuppressLint("ExecutorRegistration")
    void setOnExitAnimationListener(@Nullable SplashScreen.OnExitAnimationListener listener);
    void setOnExitAnimationListener(@NonNull SplashScreen.OnExitAnimationListener listener);

    /**
     * Clear exist listener
     * @see #setOnExitAnimationListener
     */
    void clearOnExitAnimationListener();

    /**
     * Listens for the splash screen exit event.
@@ -63,15 +69,14 @@ public interface SplashScreen {
         * of the activity. The {@link SplashScreenView} represents the splash screen view
         * object, developer can make an exit animation based on this view.</p>
         *
         * <p>If {@link SplashScreenView#remove} is not called after 5000ms, the method will be
         * automatically called and the splash screen removed.</p>
         *
         * <p>This method is never invoked if your activity sets
         * {@link #setOnExitAnimationListener} to <code>null</code>..
         * <p>This method is never invoked if your activity clear the listener by
         * {@link #clearOnExitAnimationListener}.
         *
         * @param view The view object which on top of this Activity.
         * @see #setOnExitAnimationListener
         * @see #clearOnExitAnimationListener
         */
        @UiThread
        void onSplashScreenExit(@NonNull SplashScreenView view);
    }

@@ -90,20 +95,30 @@ public interface SplashScreen {

        @Override
        public void setOnExitAnimationListener(
                @Nullable SplashScreen.OnExitAnimationListener listener) {
                @NonNull SplashScreen.OnExitAnimationListener listener) {
            if (mActivityToken == null) {
                // This is not an activity.
                return;
            }
            synchronized (mGlobal.mGlobalLock) {
                mExitAnimationListener = listener;
                if (listener != null) {
                    mExitAnimationListener = listener;
                    mGlobal.addImpl(this);
                } else {
                    mGlobal.removeImpl(this);
                }
            }
        }

        @Override
        public void clearOnExitAnimationListener() {
            if (mActivityToken == null) {
                // This is not an activity.
                return;
            }
            synchronized (mGlobal.mGlobalLock) {
                mExitAnimationListener = null;
                mGlobal.removeImpl(this);
            }
        }
    }

    /**
+39 −26
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import android.annotation.ColorInt;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.TestApi;
import android.annotation.UiThread;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
@@ -32,7 +33,6 @@ import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.SystemClock;
import android.os.Trace;
import android.util.AttributeSet;
import android.util.Log;
@@ -46,7 +46,8 @@ import android.widget.FrameLayout;
import com.android.internal.R;
import com.android.internal.policy.DecorView;

import java.util.function.Consumer;
import java.time.Duration;
import java.time.Instant;

/**
 * <p>The view which allows an activity to customize its splash screen exit animation.</p>
@@ -75,8 +76,8 @@ public final class SplashScreenView extends FrameLayout {
    private Bitmap mParceledIconBitmap;
    private View mBrandingImageView;
    private Bitmap mParceledBrandingBitmap;
    private long mIconAnimationDuration;
    private long mIconAnimationStart;
    private Duration mIconAnimationDuration;
    private Instant mIconAnimationStart;

    // The host activity when transfer view to it.
    private Activity mHostActivity;
@@ -85,6 +86,7 @@ public final class SplashScreenView extends FrameLayout {
    private boolean mDrawBarBackground;
    private int mStatusBarColor;
    private int mNavigationBarColor;
    private boolean mHasRemoved;

    /**
     * Internal builder to create a SplashScreenView object.
@@ -101,8 +103,8 @@ public final class SplashScreenView extends FrameLayout {
        private int mBrandingImageHeight;
        private Drawable mBrandingDrawable;
        private Bitmap mParceledBrandingBitmap;
        private long mIconAnimationStart;
        private long mIconAnimationDuration;
        private Instant mIconAnimationStart;
        private Duration mIconAnimationDuration;

        public Builder(@NonNull Context context) {
            mContext = context;
@@ -126,8 +128,8 @@ public final class SplashScreenView extends FrameLayout {
                        parcelable.mBrandingHeight);
                mParceledBrandingBitmap = parcelable.mBrandingBitmap;
            }
            mIconAnimationStart = parcelable.mIconAnimationStart;
            mIconAnimationDuration = parcelable.mIconAnimationDuration;
            mIconAnimationStart = Instant.ofEpochMilli(parcelable.mIconAnimationStartMillis);
            mIconAnimationDuration = Duration.ofMillis(parcelable.mIconAnimationDurationMillis);
            return this;
        }

@@ -166,8 +168,8 @@ public final class SplashScreenView extends FrameLayout {
        /**
         * Set the animation duration if icon is animatable.
         */
        public Builder setAnimationDuration(int duration) {
            mIconAnimationDuration = duration;
        public Builder setAnimationDurationMillis(int duration) {
            mIconAnimationDuration = Duration.ofMillis(duration);
            return this;
        }

@@ -203,7 +205,8 @@ public final class SplashScreenView extends FrameLayout {
            }
            if (mIconDrawable != null) {
                view.mIconView.setBackground(mIconDrawable);
                view.initIconAnimation(mIconDrawable, mIconAnimationDuration);
                view.initIconAnimation(mIconDrawable,
                        mIconAnimationDuration != null ? mIconAnimationDuration.toMillis() : 0);
            }
            view.mIconAnimationStart = mIconAnimationStart;
            view.mIconAnimationDuration = mIconAnimationDuration;
@@ -266,15 +269,16 @@ public final class SplashScreenView extends FrameLayout {
     * @see android.R.attr#windowSplashScreenAnimatedIcon
     * @see android.R.attr#windowSplashScreenAnimationDuration
     */
    public long getIconAnimationDurationMillis() {
    @Nullable
    public Duration getIconAnimationDuration() {
        return mIconAnimationDuration;
    }

    /**
     * If the replaced icon is animatable, return the animation start time in millisecond based on
     * system. The start time is set using {@link SystemClock#uptimeMillis()}.
     * If the replaced icon is animatable, return the animation start time based on system clock.
     */
    public long getIconAnimationStartMillis() {
    @Nullable
    public Instant getIconAnimationStart() {
        return mIconAnimationStart;
    }

@@ -286,8 +290,8 @@ public final class SplashScreenView extends FrameLayout {
        aniDrawable.prepareAnimate(duration, this::animationStartCallback);
    }

    private void animationStartCallback(long startAt) {
        mIconAnimationStart = startAt;
    private void animationStartCallback() {
        mIconAnimationStart = Instant.now();
    }

    /**
@@ -295,7 +299,11 @@ public final class SplashScreenView extends FrameLayout {
     * <p><strong>Do not</strong> invoke this method from a drawing method
     * ({@link #onDraw(android.graphics.Canvas)} for instance).</p>
     */
    @UiThread
    public void remove() {
        if (mHasRemoved) {
            return;
        }
        setVisibility(GONE);
        if (mParceledIconBitmap != null) {
            mIconView.setBackground(null);
@@ -321,6 +329,7 @@ public final class SplashScreenView extends FrameLayout {
        if (mHostActivity != null) {
            mHostActivity.detachSplashScreenView();
        }
        mHasRemoved = true;
    }

    /**
@@ -414,7 +423,7 @@ public final class SplashScreenView extends FrameLayout {
         * @param startListener The callback listener used to receive the start of the animation.
         * @return true if this drawable object can also be animated and it can be played now.
         */
        protected boolean prepareAnimate(long duration, Consumer<Long> startListener) {
        protected boolean prepareAnimate(long duration, Runnable startListener) {
            return false;
        }
    }
@@ -433,8 +442,8 @@ public final class SplashScreenView extends FrameLayout {
        private int mBrandingHeight;
        private Bitmap mBrandingBitmap;

        private long mIconAnimationStart;
        private long mIconAnimationDuration;
        private long mIconAnimationStartMillis;
        private long mIconAnimationDurationMillis;

        public SplashScreenViewParcelable(SplashScreenView view) {
            ViewGroup.LayoutParams params = view.getIconView().getLayoutParams();
@@ -447,8 +456,12 @@ public final class SplashScreenView extends FrameLayout {
            mBrandingWidth = params.width;
            mBrandingHeight = params.height;

            mIconAnimationStart = view.getIconAnimationStartMillis();
            mIconAnimationDuration = view.getIconAnimationDurationMillis();
            if (view.getIconAnimationStart() != null) {
                mIconAnimationStartMillis = view.getIconAnimationStart().toEpochMilli();
            }
            if (view.getIconAnimationDuration() != null) {
                mIconAnimationDurationMillis = view.getIconAnimationDuration().toMillis();
            }
        }

        private Bitmap copyDrawable(Drawable drawable) {
@@ -479,8 +492,8 @@ public final class SplashScreenView extends FrameLayout {
            mBrandingWidth = source.readInt();
            mBrandingHeight = source.readInt();
            mBrandingBitmap = source.readTypedObject(Bitmap.CREATOR);
            mIconAnimationStart = source.readLong();
            mIconAnimationDuration = source.readLong();
            mIconAnimationStartMillis = source.readLong();
            mIconAnimationDurationMillis = source.readLong();
            mIconBackground = source.readInt();
        }

@@ -497,8 +510,8 @@ public final class SplashScreenView extends FrameLayout {
            dest.writeInt(mBrandingWidth);
            dest.writeInt(mBrandingHeight);
            dest.writeTypedObject(mBrandingBitmap, flags);
            dest.writeLong(mIconAnimationStart);
            dest.writeLong(mIconAnimationDuration);
            dest.writeLong(mIconAnimationStartMillis);
            dest.writeLong(mIconAnimationDurationMillis);
            dest.writeInt(mIconBackground);
        }

+1 −1
Original line number Diff line number Diff line
@@ -357,7 +357,7 @@ public class SplashscreenContentDrawer {
            if (iconDrawable != null) {
                builder.setCenterViewDrawable(iconDrawable);
            }
            builder.setAnimationDuration(mIconAnimationDuration);
            builder.setAnimationDurationMillis(mIconAnimationDuration);
            if (mBrandingDrawable != null) {
                builder.setBrandingDrawable(mBrandingDrawable, mBrandingImageWidth,
                        mBrandingImageHeight);
+2 −7
Original line number Diff line number Diff line
@@ -37,15 +37,12 @@ import android.graphics.drawable.AdaptiveIconDrawable;
import android.graphics.drawable.Animatable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.SystemClock;
import android.os.Trace;
import android.util.PathParser;
import android.window.SplashScreenView;

import com.android.internal.R;

import java.util.function.Consumer;

/**
 * Creating a lightweight Drawable object used for splash screen.
 * @hide
@@ -133,7 +130,6 @@ public class SplashscreenIconDrawableFactory {
        private Animatable mAnimatableIcon;
        private Animator mIconAnimator;
        private boolean mAnimationTriggered;
        private long mIconAnimationStart;

        AnimatableIconDrawable(@ColorInt int backgroundColor, Drawable foregroundDrawable) {
            mForegroundDrawable = foregroundDrawable;
@@ -150,16 +146,15 @@ public class SplashscreenIconDrawableFactory {
        }

        @Override
        protected boolean prepareAnimate(long duration, Consumer<Long> startListener) {
        protected boolean prepareAnimate(long duration, Runnable startListener) {
            mAnimatableIcon = (Animatable) mForegroundDrawable;
            mIconAnimator = ValueAnimator.ofInt(0, 1);
            mIconAnimator.setDuration(duration);
            mIconAnimator.addListener(new Animator.AnimatorListener() {
                @Override
                public void onAnimationStart(Animator animation) {
                    mIconAnimationStart = SystemClock.uptimeMillis();
                    if (startListener != null) {
                        startListener.accept(mIconAnimationStart);
                        startListener.run();
                    }
                    mAnimatableIcon.start();
                }