Loading libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java +53 −4 Original line number Diff line number Diff line Loading @@ -22,6 +22,9 @@ import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_EMPTY_SPLAS import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_LEGACY_SPLASH_SCREEN; import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_SPLASH_SCREEN; import static com.android.wm.shell.startingsurface.StartingSurfaceDrawer.MAX_ANIMATION_DURATION; import static com.android.wm.shell.startingsurface.StartingSurfaceDrawer.MINIMAL_ANIMATION_DURATION; import android.annotation.ColorInt; import android.annotation.IntDef; import android.annotation.NonNull; Loading @@ -46,6 +49,7 @@ import android.graphics.drawable.LayerDrawable; import android.net.Uri; import android.os.Handler; import android.os.HandlerThread; import android.os.SystemClock; import android.os.Trace; import android.os.UserHandle; import android.util.ArrayMap; Loading Loading @@ -322,6 +326,33 @@ public class SplashscreenContentDrawer { private int mAnimationDuration = 0; } /** * Get an optimal animation duration to keep the splash screen from showing. * * @param animationDuration The animation duration defined from app. * @param appReadyDuration The real duration from the starting the app to the first app window * drawn. */ @VisibleForTesting static long getShowingDuration(long animationDuration, long appReadyDuration) { if (animationDuration <= appReadyDuration) { // app window ready took longer time than animation, it can be removed ASAP. return appReadyDuration; } if (appReadyDuration < MAX_ANIMATION_DURATION) { if (animationDuration > MAX_ANIMATION_DURATION || appReadyDuration < MINIMAL_ANIMATION_DURATION) { // animation is too long or too short, cut off with minimal duration return MINIMAL_ANIMATION_DURATION; } // animation is longer than dOpt but shorter than max, allow it to play till finish return MAX_ANIMATION_DURATION; } // the shortest duration is longer than dMax, cut off no matter how long the animation // will be. return appReadyDuration; } private class StartingWindowViewBuilder { private final Context mContext; private final ActivityInfo mActivityInfo; Loading Loading @@ -977,9 +1008,27 @@ public class SplashscreenContentDrawer { * Create and play the default exit animation for splash screen view. */ void applyExitAnimation(SplashScreenView view, SurfaceControl leash, Rect frame, Runnable finishCallback) { final SplashScreenExitAnimation animation = new SplashScreenExitAnimation(mContext, view, leash, frame, mMainWindowShiftLength, mTransactionPool, finishCallback); Rect frame, Runnable finishCallback, long createTime) { final Runnable playAnimation = () -> { final SplashScreenExitAnimation animation = new SplashScreenExitAnimation(mContext, view, leash, frame, mMainWindowShiftLength, mTransactionPool, finishCallback); animation.startAnimations(); }; if (view.getIconView() == null) { playAnimation.run(); return; } final long appReadyDuration = SystemClock.uptimeMillis() - createTime; final long animDuration = view.getIconAnimationDuration() != null ? view.getIconAnimationDuration().toMillis() : 0; final long minimumShowingDuration = getShowingDuration(animDuration, appReadyDuration); final long delayed = minimumShowingDuration - appReadyDuration; ProtoLog.v(ShellProtoLogGroup.WM_SHELL_STARTING_WINDOW, "applyExitAnimation delayed: %s", delayed); if (delayed > 0) { view.postDelayed(playAnimation, delayed); } else { playAnimation.run(); } } } libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java +24 −1 Original line number Diff line number Diff line Loading @@ -41,6 +41,7 @@ import android.hardware.display.DisplayManager; import android.os.IBinder; import android.os.RemoteCallback; import android.os.RemoteException; import android.os.SystemClock; import android.os.Trace; import android.os.UserHandle; import android.util.Slog; Loading Loading @@ -120,6 +121,25 @@ public class StartingSurfaceDrawer { private StartingSurface.SysuiProxy mSysuiProxy; private final StartingWindowRemovalInfo mTmpRemovalInfo = new StartingWindowRemovalInfo(); /** * The minimum duration during which the splash screen is shown when the splash screen icon is * animated. */ static final long MINIMAL_ANIMATION_DURATION = 400L; /** * Allow the icon style splash screen to be displayed for longer to give time for the animation * to finish, i.e. the extra buffer time to keep the splash screen if the animation is slightly * longer than the {@link #MINIMAL_ANIMATION_DURATION} duration. */ static final long TIME_WINDOW_DURATION = 100L; /** * The maximum duration during which the splash screen will be shown if the application is ready * to show before the icon animation finishes. */ static final long MAX_ANIMATION_DURATION = MINIMAL_ANIMATION_DURATION + TIME_WINDOW_DURATION; /** * @param splashScreenExecutor The thread used to control add and remove starting window. */ Loading Loading @@ -593,7 +613,8 @@ public class StartingSurfaceDrawer { if (removalInfo.playRevealAnimation) { mSplashscreenContentDrawer.applyExitAnimation(record.mContentView, removalInfo.windowAnimationLeash, removalInfo.mainFrame, () -> removeWindowInner(record.mDecorView, true)); () -> removeWindowInner(record.mDecorView, true), record.mCreateTime); } else { // the SplashScreenView has been copied to client, hide the view to skip // default exit animation Loading Loading @@ -641,6 +662,7 @@ public class StartingSurfaceDrawer { private boolean mSetSplashScreen; private @StartingWindowType int mSuggestType; private int mBGColor; private final long mCreateTime; StartingWindowRecord(IBinder appToken, View decorView, TaskSnapshotWindow taskSnapshotWindow, @StartingWindowType int suggestType) { Loading @@ -651,6 +673,7 @@ public class StartingSurfaceDrawer { mBGColor = mTaskSnapshotWindow.getBackgroundColor(); } mSuggestType = suggestType; mCreateTime = SystemClock.uptimeMillis(); } private void setSplashScreenView(SplashScreenView splashScreenView) { Loading libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java +52 −0 Original line number Diff line number Diff line Loading @@ -24,6 +24,8 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.wm.shell.startingsurface.StartingSurfaceDrawer.MAX_ANIMATION_DURATION; import static com.android.wm.shell.startingsurface.StartingSurfaceDrawer.MINIMAL_ANIMATION_DURATION; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; Loading Loading @@ -297,6 +299,56 @@ public class StartingSurfaceDrawerTests { assertEquals(mStartingSurfaceDrawer.mStartingWindowRecords.size(), 0); } @Test public void testMinimumAnimationDuration() { final long maxDuration = MAX_ANIMATION_DURATION; final long minDuration = MINIMAL_ANIMATION_DURATION; final long shortDuration = minDuration - 1; final long medianShortDuration = minDuration + 1; final long medianLongDuration = maxDuration - 1; final long longAppDuration = maxDuration + 1; // static icon assertEquals(shortDuration, SplashscreenContentDrawer.getShowingDuration( 0, shortDuration)); // median launch + static icon assertEquals(medianShortDuration, SplashscreenContentDrawer.getShowingDuration( 0, medianShortDuration)); // long launch + static icon assertEquals(longAppDuration, SplashscreenContentDrawer.getShowingDuration( 0, longAppDuration)); // fast launch + animatable icon assertEquals(shortDuration, SplashscreenContentDrawer.getShowingDuration( shortDuration, shortDuration)); assertEquals(minDuration, SplashscreenContentDrawer.getShowingDuration( medianShortDuration, shortDuration)); assertEquals(minDuration, SplashscreenContentDrawer.getShowingDuration( longAppDuration, shortDuration)); // median launch + animatable icon assertEquals(medianShortDuration, SplashscreenContentDrawer.getShowingDuration( shortDuration, medianShortDuration)); assertEquals(medianShortDuration, SplashscreenContentDrawer.getShowingDuration( medianShortDuration, medianShortDuration)); assertEquals(minDuration, SplashscreenContentDrawer.getShowingDuration( longAppDuration, medianShortDuration)); // between min < max launch + animatable icon assertEquals(medianLongDuration, SplashscreenContentDrawer.getShowingDuration( medianShortDuration, medianLongDuration)); assertEquals(maxDuration, SplashscreenContentDrawer.getShowingDuration( medianLongDuration, medianShortDuration)); // long launch + animatable icon assertEquals(longAppDuration, SplashscreenContentDrawer.getShowingDuration( shortDuration, longAppDuration)); assertEquals(longAppDuration, SplashscreenContentDrawer.getShowingDuration( medianShortDuration, longAppDuration)); assertEquals(longAppDuration, SplashscreenContentDrawer.getShowingDuration( longAppDuration, longAppDuration)); } private StartingWindowInfo createWindowInfo(int taskId, int themeResId) { StartingWindowInfo windowInfo = new StartingWindowInfo(); final ActivityInfo info = new ActivityInfo(); Loading Loading
libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java +53 −4 Original line number Diff line number Diff line Loading @@ -22,6 +22,9 @@ import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_EMPTY_SPLAS import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_LEGACY_SPLASH_SCREEN; import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_SPLASH_SCREEN; import static com.android.wm.shell.startingsurface.StartingSurfaceDrawer.MAX_ANIMATION_DURATION; import static com.android.wm.shell.startingsurface.StartingSurfaceDrawer.MINIMAL_ANIMATION_DURATION; import android.annotation.ColorInt; import android.annotation.IntDef; import android.annotation.NonNull; Loading @@ -46,6 +49,7 @@ import android.graphics.drawable.LayerDrawable; import android.net.Uri; import android.os.Handler; import android.os.HandlerThread; import android.os.SystemClock; import android.os.Trace; import android.os.UserHandle; import android.util.ArrayMap; Loading Loading @@ -322,6 +326,33 @@ public class SplashscreenContentDrawer { private int mAnimationDuration = 0; } /** * Get an optimal animation duration to keep the splash screen from showing. * * @param animationDuration The animation duration defined from app. * @param appReadyDuration The real duration from the starting the app to the first app window * drawn. */ @VisibleForTesting static long getShowingDuration(long animationDuration, long appReadyDuration) { if (animationDuration <= appReadyDuration) { // app window ready took longer time than animation, it can be removed ASAP. return appReadyDuration; } if (appReadyDuration < MAX_ANIMATION_DURATION) { if (animationDuration > MAX_ANIMATION_DURATION || appReadyDuration < MINIMAL_ANIMATION_DURATION) { // animation is too long or too short, cut off with minimal duration return MINIMAL_ANIMATION_DURATION; } // animation is longer than dOpt but shorter than max, allow it to play till finish return MAX_ANIMATION_DURATION; } // the shortest duration is longer than dMax, cut off no matter how long the animation // will be. return appReadyDuration; } private class StartingWindowViewBuilder { private final Context mContext; private final ActivityInfo mActivityInfo; Loading Loading @@ -977,9 +1008,27 @@ public class SplashscreenContentDrawer { * Create and play the default exit animation for splash screen view. */ void applyExitAnimation(SplashScreenView view, SurfaceControl leash, Rect frame, Runnable finishCallback) { final SplashScreenExitAnimation animation = new SplashScreenExitAnimation(mContext, view, leash, frame, mMainWindowShiftLength, mTransactionPool, finishCallback); Rect frame, Runnable finishCallback, long createTime) { final Runnable playAnimation = () -> { final SplashScreenExitAnimation animation = new SplashScreenExitAnimation(mContext, view, leash, frame, mMainWindowShiftLength, mTransactionPool, finishCallback); animation.startAnimations(); }; if (view.getIconView() == null) { playAnimation.run(); return; } final long appReadyDuration = SystemClock.uptimeMillis() - createTime; final long animDuration = view.getIconAnimationDuration() != null ? view.getIconAnimationDuration().toMillis() : 0; final long minimumShowingDuration = getShowingDuration(animDuration, appReadyDuration); final long delayed = minimumShowingDuration - appReadyDuration; ProtoLog.v(ShellProtoLogGroup.WM_SHELL_STARTING_WINDOW, "applyExitAnimation delayed: %s", delayed); if (delayed > 0) { view.postDelayed(playAnimation, delayed); } else { playAnimation.run(); } } }
libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java +24 −1 Original line number Diff line number Diff line Loading @@ -41,6 +41,7 @@ import android.hardware.display.DisplayManager; import android.os.IBinder; import android.os.RemoteCallback; import android.os.RemoteException; import android.os.SystemClock; import android.os.Trace; import android.os.UserHandle; import android.util.Slog; Loading Loading @@ -120,6 +121,25 @@ public class StartingSurfaceDrawer { private StartingSurface.SysuiProxy mSysuiProxy; private final StartingWindowRemovalInfo mTmpRemovalInfo = new StartingWindowRemovalInfo(); /** * The minimum duration during which the splash screen is shown when the splash screen icon is * animated. */ static final long MINIMAL_ANIMATION_DURATION = 400L; /** * Allow the icon style splash screen to be displayed for longer to give time for the animation * to finish, i.e. the extra buffer time to keep the splash screen if the animation is slightly * longer than the {@link #MINIMAL_ANIMATION_DURATION} duration. */ static final long TIME_WINDOW_DURATION = 100L; /** * The maximum duration during which the splash screen will be shown if the application is ready * to show before the icon animation finishes. */ static final long MAX_ANIMATION_DURATION = MINIMAL_ANIMATION_DURATION + TIME_WINDOW_DURATION; /** * @param splashScreenExecutor The thread used to control add and remove starting window. */ Loading Loading @@ -593,7 +613,8 @@ public class StartingSurfaceDrawer { if (removalInfo.playRevealAnimation) { mSplashscreenContentDrawer.applyExitAnimation(record.mContentView, removalInfo.windowAnimationLeash, removalInfo.mainFrame, () -> removeWindowInner(record.mDecorView, true)); () -> removeWindowInner(record.mDecorView, true), record.mCreateTime); } else { // the SplashScreenView has been copied to client, hide the view to skip // default exit animation Loading Loading @@ -641,6 +662,7 @@ public class StartingSurfaceDrawer { private boolean mSetSplashScreen; private @StartingWindowType int mSuggestType; private int mBGColor; private final long mCreateTime; StartingWindowRecord(IBinder appToken, View decorView, TaskSnapshotWindow taskSnapshotWindow, @StartingWindowType int suggestType) { Loading @@ -651,6 +673,7 @@ public class StartingSurfaceDrawer { mBGColor = mTaskSnapshotWindow.getBackgroundColor(); } mSuggestType = suggestType; mCreateTime = SystemClock.uptimeMillis(); } private void setSplashScreenView(SplashScreenView splashScreenView) { Loading
libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java +52 −0 Original line number Diff line number Diff line Loading @@ -24,6 +24,8 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.wm.shell.startingsurface.StartingSurfaceDrawer.MAX_ANIMATION_DURATION; import static com.android.wm.shell.startingsurface.StartingSurfaceDrawer.MINIMAL_ANIMATION_DURATION; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; Loading Loading @@ -297,6 +299,56 @@ public class StartingSurfaceDrawerTests { assertEquals(mStartingSurfaceDrawer.mStartingWindowRecords.size(), 0); } @Test public void testMinimumAnimationDuration() { final long maxDuration = MAX_ANIMATION_DURATION; final long minDuration = MINIMAL_ANIMATION_DURATION; final long shortDuration = minDuration - 1; final long medianShortDuration = minDuration + 1; final long medianLongDuration = maxDuration - 1; final long longAppDuration = maxDuration + 1; // static icon assertEquals(shortDuration, SplashscreenContentDrawer.getShowingDuration( 0, shortDuration)); // median launch + static icon assertEquals(medianShortDuration, SplashscreenContentDrawer.getShowingDuration( 0, medianShortDuration)); // long launch + static icon assertEquals(longAppDuration, SplashscreenContentDrawer.getShowingDuration( 0, longAppDuration)); // fast launch + animatable icon assertEquals(shortDuration, SplashscreenContentDrawer.getShowingDuration( shortDuration, shortDuration)); assertEquals(minDuration, SplashscreenContentDrawer.getShowingDuration( medianShortDuration, shortDuration)); assertEquals(minDuration, SplashscreenContentDrawer.getShowingDuration( longAppDuration, shortDuration)); // median launch + animatable icon assertEquals(medianShortDuration, SplashscreenContentDrawer.getShowingDuration( shortDuration, medianShortDuration)); assertEquals(medianShortDuration, SplashscreenContentDrawer.getShowingDuration( medianShortDuration, medianShortDuration)); assertEquals(minDuration, SplashscreenContentDrawer.getShowingDuration( longAppDuration, medianShortDuration)); // between min < max launch + animatable icon assertEquals(medianLongDuration, SplashscreenContentDrawer.getShowingDuration( medianShortDuration, medianLongDuration)); assertEquals(maxDuration, SplashscreenContentDrawer.getShowingDuration( medianLongDuration, medianShortDuration)); // long launch + animatable icon assertEquals(longAppDuration, SplashscreenContentDrawer.getShowingDuration( shortDuration, longAppDuration)); assertEquals(longAppDuration, SplashscreenContentDrawer.getShowingDuration( medianShortDuration, longAppDuration)); assertEquals(longAppDuration, SplashscreenContentDrawer.getShowingDuration( longAppDuration, longAppDuration)); } private StartingWindowInfo createWindowInfo(int taskId, int themeResId) { StartingWindowInfo windowInfo = new StartingWindowInfo(); final ActivityInfo info = new ActivityInfo(); Loading