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
This commit is contained in:
wilsonshih
2021-02-04 18:01:31 +08:00
committed by Vadim Caen
parent a8e4cd6c6f
commit bfb28f2f3c
4 changed files with 43 additions and 92 deletions

View File

@@ -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();
}

View File

@@ -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 {

View File

@@ -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 =

View File

@@ -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);
}
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);