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
diff --git a/core/api/current.txt b/core/api/current.txt
index 25e1838..d848bbf 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -55842,6 +55842,8 @@
   }
 
   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();
   }
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 3e2accc..29be5c6 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -2731,7 +2731,6 @@
 
   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 {
diff --git a/core/java/android/window/SplashScreenView.java b/core/java/android/window/SplashScreenView.java
index 5292875..35ccfca 100644
--- a/core/java/android/window/SplashScreenView.java
+++ b/core/java/android/window/SplashScreenView.java
@@ -33,6 +33,7 @@
 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 @@
     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 @@
         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 @@
                         parcelable.mBrandingHeight);
                 mParceledBrandingBitmap = parcelable.mBrandingBitmap;
             }
+            mIconAnimationStart = parcelable.mIconAnimationStart;
+            mIconAnimationDuration = parcelable.mIconAnimationDuration;
             return this;
         }
 
@@ -186,6 +191,8 @@
                 view.mIconView.setBackground(mIconDrawable);
                 view.initIconAnimation(mIconDrawable, mIconAnimationDuration);
             }
+            view.mIconAnimationStart = mIconAnimationStart;
+            view.mIconAnimationDuration = mIconAnimationDuration;
             if (mParceledIconBitmap != null) {
                 view.mParceledIconBitmap = mParceledIconBitmap;
             }
@@ -238,28 +245,44 @@
         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 @@
         }
     }
 
-    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 @@
         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 @@
             mBrandingWidth = params.width;
             mBrandingHeight = params.height;
 
+            mIconAnimationStart = view.getIconAnimationStartMillis();
+            mIconAnimationDuration = view.getIconAnimationDurationMillis();
         }
 
         private Bitmap copyDrawable(Drawable drawable) {
@@ -444,6 +454,8 @@
             mBrandingWidth = source.readInt();
             mBrandingHeight = source.readInt();
             mBrandingBitmap = source.readTypedObject(Bitmap.CREATOR);
+            mIconAnimationStart = source.readLong();
+            mIconAnimationDuration = source.readLong();
         }
 
         @Override
@@ -459,6 +471,8 @@
             dest.writeInt(mBrandingWidth);
             dest.writeInt(mBrandingHeight);
             dest.writeTypedObject(mBrandingBitmap, flags);
+            dest.writeLong(mIconAnimationStart);
+            dest.writeLong(mIconAnimationDuration);
         }
 
         public static final @NonNull Parcelable.Creator<SplashScreenViewParcelable> CREATOR =
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
index 8fe1c6e..5332291 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
@@ -74,8 +74,6 @@
     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 @@
         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);
-            }
+            parcelable = new SplashScreenViewParcelable(preView.mContentView);
         } else {
             parcelable = null;
         }
@@ -460,60 +449,12 @@
                 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 @@
                 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);