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

Commit bfb28f2f authored by wilsonshih's avatar wilsonshih Committed by Vadim Caen
Browse files

Add two more Api for SplashScreenView(7/N)

getIconAnimationDuration - Returns the duration of the icon animation
if icon is animatable.
getIconAnimationStart - If the replaced icon is animatable, return
the animation start time in millisecond based on system.

Bug: 73289295
Test: atest CtsWindowManagerDeviceTestCases:SplashscreenTests
Change-Id: Ie4332d6764b4d0892a0e5e6f7c297102b71a79f9
parent a8e4cd6c
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -55842,6 +55842,8 @@ package android.window {
  }
  public final class SplashScreenView extends android.widget.FrameLayout {
    method public long getIconAnimationDurationMillis();
    method public long getIconAnimationStartMillis();
    method @Nullable public android.view.View getIconView();
    method public void remove();
  }
+0 −1
Original line number Diff line number Diff line
@@ -2731,7 +2731,6 @@ package android.window {

  public final class SplashScreenView extends android.widget.FrameLayout {
    method @Nullable public android.view.View getBrandingView();
    method public boolean isIconAnimating();
  }

  public final class StartingWindowInfo implements android.os.Parcelable {
+39 −25
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@ import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.SystemClock;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
@@ -71,10 +72,11 @@ public final class SplashScreenView extends FrameLayout {
    private Bitmap mParceledIconBitmap;
    private View mBrandingImageView;
    private Bitmap mParceledBrandingBitmap;
    private long mIconAnimationDuration;
    private long mIconAnimationStart;

    private Animatable mAnimatableIcon;
    private ValueAnimator mAnimator;
    private Runnable mAnimationFinishListener;

    // cache original window and status
    private Window mWindow;
@@ -92,11 +94,12 @@ public final class SplashScreenView extends FrameLayout {
        private @ColorInt int mBackgroundColor;
        private Bitmap mParceledIconBitmap;
        private Drawable mIconDrawable;
        private int mIconAnimationDuration;
        private int mBrandingImageWidth;
        private int mBrandingImageHeight;
        private Drawable mBrandingDrawable;
        private Bitmap mParceledBrandingBitmap;
        private long mIconAnimationStart;
        private long mIconAnimationDuration;

        public Builder(@NonNull Context context) {
            mContext = context;
@@ -119,6 +122,8 @@ public final class SplashScreenView extends FrameLayout {
                        parcelable.mBrandingHeight);
                mParceledBrandingBitmap = parcelable.mBrandingBitmap;
            }
            mIconAnimationStart = parcelable.mIconAnimationStart;
            mIconAnimationDuration = parcelable.mIconAnimationDuration;
            return this;
        }

@@ -186,6 +191,8 @@ public final class SplashScreenView extends FrameLayout {
                view.mIconView.setBackground(mIconDrawable);
                view.initIconAnimation(mIconDrawable, mIconAnimationDuration);
            }
            view.mIconAnimationStart = mIconAnimationStart;
            view.mIconAnimationDuration = mIconAnimationDuration;
            if (mParceledIconBitmap != null) {
                view.mParceledIconBitmap = mParceledIconBitmap;
            }
@@ -238,28 +245,44 @@ public final class SplashScreenView extends FrameLayout {
        return !mNotCopyable;
    }

    void initIconAnimation(Drawable iconDrawable, int duration) {
    /**
     * Returns the duration of the icon animation if icon is animatable.
     *
     * @see android.R.attr#windowSplashScreenAnimatedIcon
     * @see android.R.attr#windowSplashScreenAnimationDuration
     */
    public long getIconAnimationDurationMillis() {
        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()}.
     */
    public long getIconAnimationStartMillis() {
        return mIconAnimationStart;
    }

    void initIconAnimation(Drawable iconDrawable, long duration) {
        if (iconDrawable instanceof Animatable) {
            mAnimatableIcon = (Animatable) iconDrawable;
            mAnimator = ValueAnimator.ofInt(0, 1);
            mAnimator.setDuration(duration);

            mAnimator.addListener(new Animator.AnimatorListener() {
                @Override
                public void onAnimationStart(Animator animation) {
                    mIconAnimationStart = SystemClock.uptimeMillis();
                    mAnimatableIcon.start();
                }

                @Override
                public void onAnimationEnd(Animator animation) {
                    mAnimatableIcon.stop();
                    onIconAnimationFinish();
                }

                @Override
                public void onAnimationCancel(Animator animation) {
                    mAnimatableIcon.stop();
                    onIconAnimationFinish();
                }

                @Override
@@ -271,30 +294,12 @@ public final class SplashScreenView extends FrameLayout {
        }
    }

    private void onIconAnimationFinish() {
        if (mAnimationFinishListener != null) {
            mAnimationFinishListener.run();
            mAnimationFinishListener = null;
        }
    }

    /**
     * @hide
     */
    @TestApi
    public boolean isIconAnimating() {
        return mAnimatableIcon != null && mAnimator.isRunning();
    }

    /**
     * @hide
     */
    public void startIntroAnimation(Runnable finishListener) {
    public void startIntroAnimation() {
        if (mAnimatableIcon != null) {
            mAnimationFinishListener = finishListener;
            mAnimator.start();
        } else if (finishListener != null) {
            finishListener.run();
        }
    }

@@ -403,6 +408,9 @@ public final class SplashScreenView extends FrameLayout {
        private int mBrandingHeight;
        private Bitmap mBrandingBitmap;

        private long mIconAnimationStart;
        private long mIconAnimationDuration;

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

            mIconAnimationStart = view.getIconAnimationStartMillis();
            mIconAnimationDuration = view.getIconAnimationDurationMillis();
        }

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

        @Override
@@ -459,6 +471,8 @@ public final class SplashScreenView extends FrameLayout {
            dest.writeInt(mBrandingWidth);
            dest.writeInt(mBrandingHeight);
            dest.writeTypedObject(mBrandingBitmap, flags);
            dest.writeLong(mIconAnimationStart);
            dest.writeLong(mIconAnimationDuration);
        }

        public static final @NonNull Parcelable.Creator<SplashScreenViewParcelable> CREATOR =
+2 −66
Original line number Diff line number Diff line
@@ -74,8 +74,6 @@ public class StartingSurfaceDrawer {
    private final DisplayManager mDisplayManager;
    final ShellExecutor mMainExecutor;
    private final SplashscreenContentDrawer mSplashscreenContentDrawer;
    private final IconAnimationFinishListener mIconAnimationFinishListener =
            new IconAnimationFinishListener();

    // TODO(b/131727939) remove this when clearing ActivityRecord
    private static final int REMOVE_WHEN_TIMEOUT = 2000;
@@ -410,16 +408,7 @@ public class StartingSurfaceDrawer {
        SplashScreenViewParcelable parcelable;
        if (preView != null && preView.mContentView != null
                && preView.mContentView.isCopyable()) {
            if (preView.mContentView.isIconAnimating()) {
                // if animating, wait until animation finish
                if (DEBUG_SPLASH_SCREEN) {
                    Slog.v(TAG, "Copying splash screen view but icon is animating " + taskId);
                }
                mIconAnimationFinishListener.waitingForCopyTask(taskId);
                return;
            } else {
            parcelable = new SplashScreenViewParcelable(preView.mContentView);
            }
        } else {
            parcelable = null;
        }
@@ -460,60 +449,12 @@ public class StartingSurfaceDrawer {
                mMainExecutor.executeDelayed(() -> removeWindowSynced(taskId), REMOVE_WHEN_TIMEOUT);
                final StartingWindowRecord tView = new StartingWindowRecord(view,
                        null /* TaskSnapshotWindow */, splashScreenView);
                splashScreenView.startIntroAnimation(
                        mIconAnimationFinishListener.makeListener(taskId));
                splashScreenView.startIntroAnimation();
                mStartingWindowRecords.put(taskId, tView);
            }
        });
    }

    private class IconAnimationFinishListener {
        private final SparseArray<TaskListener> mListeners = new SparseArray<>();

        private class TaskListener implements Runnable {
            private int mTargetTaskId;
            private boolean mWaitingForCopy;
            private boolean mWaitingForRemove;
            @Override
            public void run() {
                if (mWaitingForCopy) {
                    if (DEBUG_SPLASH_SCREEN) {
                        Slog.v(TAG, "Icon animation finish and waiting for copy at task "
                                + mTargetTaskId);
                    }
                    copySplashScreenView(mTargetTaskId);
                }
                if (mWaitingForRemove) {
                    if (DEBUG_SPLASH_SCREEN) {
                        Slog.v(TAG, "Icon animation finish and waiting for remove at task "
                                + mTargetTaskId);
                    }
                    mMainExecutor.execute(() -> removeWindowSynced(mTargetTaskId));
                }
                mListeners.remove(mTargetTaskId);
            }
        }

        private Runnable makeListener(int taskId) {
            final TaskListener listener = new TaskListener();
            listener.mTargetTaskId = taskId;
            mListeners.put(taskId, listener);
            return listener;
        }

        private void waitingForCopyTask(int taskId) {
            if (mListeners.contains(taskId)) {
                mListeners.get(taskId).mWaitingForCopy = true;
            }
        }

        private void waitingForRemove(int taskId) {
            if (mListeners.contains(taskId)) {
                mListeners.get(taskId).mWaitingForRemove = true;
            }
        }
    }

    protected void removeWindowSynced(int taskId) {
        final StartingWindowRecord record = mStartingWindowRecords.get(taskId);
        if (record != null) {
@@ -521,11 +462,6 @@ public class StartingSurfaceDrawer {
                if (DEBUG_SPLASH_SCREEN) {
                    Slog.v(TAG, "Removing splash screen window for task: " + taskId);
                }
                if (record.mContentView != null && record.mContentView.isIconAnimating()) {
                    // do not remove until the animation is finish
                    mIconAnimationFinishListener.waitingForRemove(taskId);
                    return;
                }
                final WindowManager wm = record.mDecorView.getContext()
                        .getSystemService(WindowManager.class);
                wm.removeView(record.mDecorView);