Loading core/java/android/window/SplashScreenView.java +42 −11 Original line number Diff line number Diff line Loading @@ -59,6 +59,7 @@ import com.android.internal.util.ContrastColorUtil; import java.time.Duration; import java.time.Instant; import java.util.function.Consumer; /** * <p>The view which allows an activity to customize its splash screen exit animation.</p> Loading Loading @@ -144,6 +145,7 @@ public final class SplashScreenView extends FrameLayout { private Bitmap mParceledBrandingBitmap; private Instant mIconAnimationStart; private Duration mIconAnimationDuration; private Consumer<Runnable> mUiThreadInitTask; public Builder(@NonNull Context context) { mContext = context; Loading Loading @@ -231,6 +233,15 @@ public final class SplashScreenView extends FrameLayout { return this; } /** * Set the Runnable that can receive the task which should be executed on UI thread. * @param uiThreadInitTask */ public Builder setUiThreadInitConsumer(Consumer<Runnable> uiThreadInitTask) { mUiThreadInitTask = uiThreadInitTask; return this; } /** * Set the Drawable object and size for the branding view. */ Loading Loading @@ -262,7 +273,11 @@ public final class SplashScreenView extends FrameLayout { // center icon if (mIconDrawable instanceof SplashScreenView.IconAnimateListener || mSurfacePackage != null) { if (mUiThreadInitTask != null) { mUiThreadInitTask.accept(() -> view.mIconView = createSurfaceView(view)); } else { view.mIconView = createSurfaceView(view); } view.initIconAnimation(mIconDrawable, mIconAnimationDuration != null ? mIconAnimationDuration.toMillis() : 0); view.mIconAnimationStart = mIconAnimationStart; Loading Loading @@ -316,6 +331,7 @@ public final class SplashScreenView extends FrameLayout { } private SurfaceView createSurfaceView(@NonNull SplashScreenView view) { Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "SplashScreenView#createSurfaceView"); final Context viewContext = view.getContext(); final SurfaceView surfaceView = new SurfaceView(viewContext); surfaceView.setPadding(0, 0, 0, 0); Loading Loading @@ -361,6 +377,7 @@ public final class SplashScreenView extends FrameLayout { view.addView(surfaceView); view.mSurfaceView = surfaceView; Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); return surfaceView; } } Loading Loading @@ -532,23 +549,32 @@ public final class SplashScreenView extends FrameLayout { private void releaseAnimationSurfaceHost() { if (mSurfaceHost != null && !mIsCopied) { final SurfaceControlViewHost finalSurfaceHost = mSurfaceHost; mSurfaceHost = null; finalSurfaceHost.getView().post(() -> { if (DEBUG) { Log.d(TAG, "Shell removed splash screen." + " Releasing SurfaceControlViewHost on thread #" + Thread.currentThread().getId()); } finalSurfaceHost.release(); }); releaseIconHost(mSurfaceHost); mSurfaceHost = null; } else if (mSurfacePackage != null && mSurfaceHost == null) { mSurfacePackage = null; mClientCallback.sendResult(null); } } /** * Release the host which hold the SurfaceView of the icon. * @hide */ public static void releaseIconHost(SurfaceControlViewHost host) { final Drawable background = host.getView().getBackground(); if (background instanceof SplashScreenView.IconAnimateListener) { ((SplashScreenView.IconAnimateListener) background).stopAnimation(); } host.release(); } /** * Called when this view is attached to an activity. This also makes SystemUI colors * transparent so the content of splash screen view can draw fully. Loading Loading @@ -640,6 +666,11 @@ public final class SplashScreenView extends FrameLayout { * @return true if this drawable object can also be animated and it can be played now. */ boolean prepareAnimate(long duration, Runnable startListener); /** * Stop animation. */ void stopAnimation(); } /** Loading libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java +17 −6 Original line number Diff line number Diff line Loading @@ -138,12 +138,14 @@ public class SplashscreenContentDrawer { * null if failed. */ void createContentView(Context context, @StartingWindowType int suggestType, ActivityInfo info, int taskId, Consumer<SplashScreenView> splashScreenViewConsumer) { int taskId, Consumer<SplashScreenView> splashScreenViewConsumer, Consumer<Runnable> uiThreadInitConsumer) { mSplashscreenWorkerHandler.post(() -> { SplashScreenView contentView; try { Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "makeSplashScreenContentView"); contentView = makeSplashScreenContentView(context, info, suggestType); contentView = makeSplashScreenContentView(context, info, suggestType, uiThreadInitConsumer); Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); } catch (RuntimeException e) { Slog.w(TAG, "failed creating starting window content at taskId: " Loading Loading @@ -239,7 +241,7 @@ public class SplashscreenContentDrawer { } private SplashScreenView makeSplashScreenContentView(Context context, ActivityInfo ai, @StartingWindowType int suggestType) { @StartingWindowType int suggestType, Consumer<Runnable> uiThreadInitConsumer) { updateDensity(); getWindowAttrs(context, mTmpAttrs); Loading @@ -254,6 +256,7 @@ public class SplashscreenContentDrawer { .setWindowBGColor(themeBGColor) .overlayDrawable(legacyDrawable) .chooseStyle(suggestType) .setUiThreadInitConsumer(uiThreadInitConsumer) .build(); } Loading Loading @@ -324,6 +327,7 @@ public class SplashscreenContentDrawer { private int mThemeColor; private Drawable[] mFinalIconDrawables; private int mFinalIconSize = mIconSize; private Consumer<Runnable> mUiThreadInitTask; StartingWindowViewBuilder(@NonNull Context context, @NonNull ActivityInfo aInfo) { mContext = context; Loading @@ -345,6 +349,11 @@ public class SplashscreenContentDrawer { return this; } StartingWindowViewBuilder setUiThreadInitConsumer(Consumer<Runnable> uiThreadInitTask) { mUiThreadInitTask = uiThreadInitTask; return this; } SplashScreenView build() { Drawable iconDrawable; final int animationDuration; Loading Loading @@ -391,7 +400,8 @@ public class SplashscreenContentDrawer { animationDuration = 0; } return fillViewWithIcon(mFinalIconSize, mFinalIconDrawables, animationDuration); return fillViewWithIcon(mFinalIconSize, mFinalIconDrawables, animationDuration, mUiThreadInitTask); } private class ShapeIconFactory extends BaseIconFactory { Loading Loading @@ -469,7 +479,7 @@ public class SplashscreenContentDrawer { } private SplashScreenView fillViewWithIcon(int iconSize, @Nullable Drawable[] iconDrawable, int animationDuration) { int animationDuration, Consumer<Runnable> uiThreadInitTask) { Drawable foreground = null; Drawable background = null; if (iconDrawable != null) { Loading @@ -485,7 +495,8 @@ public class SplashscreenContentDrawer { .setIconSize(iconSize) .setIconBackground(background) .setCenterViewDrawable(foreground) .setAnimationDurationMillis(animationDuration); .setAnimationDurationMillis(animationDuration) .setUiThreadInitConsumer(uiThreadInitTask); if (mSuggestType == STARTING_WINDOW_TYPE_SPLASH_SCREEN && mTmpAttrs.mBrandingImage != null) { Loading libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java +7 −0 Original line number Diff line number Diff line Loading @@ -304,6 +304,13 @@ public class SplashscreenIconDrawableFactory { return true; } @Override public void stopAnimation() { if (mIconAnimator != null) { mIconAnimator.end(); } } private final Callback mCallback = new Callback() { @Override public void invalidateDrawable(@NonNull Drawable who) { Loading libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java +13 −2 Original line number Diff line number Diff line Loading @@ -332,7 +332,7 @@ public class StartingSurfaceDrawer { mSysuiProxy.requestTopUi(true, TAG); } mSplashscreenContentDrawer.createContentView(context, suggestType, activityInfo, taskId, viewSupplier::setView); viewSupplier::setView, viewSupplier::setUiThreadInitTask); try { if (addWindow(taskId, appToken, rootLayout, display, params, suggestType)) { // We use the splash screen worker thread to create SplashScreenView while adding Loading Loading @@ -367,6 +367,7 @@ public class StartingSurfaceDrawer { private static class SplashScreenViewSupplier implements Supplier<SplashScreenView> { private SplashScreenView mView; private boolean mIsViewSet; private Runnable mUiThreadInitTask; void setView(SplashScreenView view) { synchronized (this) { mView = view; Loading @@ -375,6 +376,12 @@ public class StartingSurfaceDrawer { } } void setUiThreadInitTask(Runnable initTask) { synchronized (this) { mUiThreadInitTask = initTask; } } @Override public @Nullable SplashScreenView get() { synchronized (this) { Loading @@ -384,6 +391,10 @@ public class StartingSurfaceDrawer { } catch (InterruptedException ignored) { } } if (mUiThreadInitTask != null) { mUiThreadInitTask.run(); mUiThreadInitTask = null; } return mView; } } Loading Loading @@ -506,7 +517,7 @@ public class StartingSurfaceDrawer { Slog.v(TAG, reason + "the splash screen. Releasing SurfaceControlViewHost for task:" + taskId); } viewHost.getView().post(viewHost::release); SplashScreenView.releaseIconHost(viewHost); } protected boolean addWindow(int taskId, IBinder appToken, View view, Display display, Loading Loading
core/java/android/window/SplashScreenView.java +42 −11 Original line number Diff line number Diff line Loading @@ -59,6 +59,7 @@ import com.android.internal.util.ContrastColorUtil; import java.time.Duration; import java.time.Instant; import java.util.function.Consumer; /** * <p>The view which allows an activity to customize its splash screen exit animation.</p> Loading Loading @@ -144,6 +145,7 @@ public final class SplashScreenView extends FrameLayout { private Bitmap mParceledBrandingBitmap; private Instant mIconAnimationStart; private Duration mIconAnimationDuration; private Consumer<Runnable> mUiThreadInitTask; public Builder(@NonNull Context context) { mContext = context; Loading Loading @@ -231,6 +233,15 @@ public final class SplashScreenView extends FrameLayout { return this; } /** * Set the Runnable that can receive the task which should be executed on UI thread. * @param uiThreadInitTask */ public Builder setUiThreadInitConsumer(Consumer<Runnable> uiThreadInitTask) { mUiThreadInitTask = uiThreadInitTask; return this; } /** * Set the Drawable object and size for the branding view. */ Loading Loading @@ -262,7 +273,11 @@ public final class SplashScreenView extends FrameLayout { // center icon if (mIconDrawable instanceof SplashScreenView.IconAnimateListener || mSurfacePackage != null) { if (mUiThreadInitTask != null) { mUiThreadInitTask.accept(() -> view.mIconView = createSurfaceView(view)); } else { view.mIconView = createSurfaceView(view); } view.initIconAnimation(mIconDrawable, mIconAnimationDuration != null ? mIconAnimationDuration.toMillis() : 0); view.mIconAnimationStart = mIconAnimationStart; Loading Loading @@ -316,6 +331,7 @@ public final class SplashScreenView extends FrameLayout { } private SurfaceView createSurfaceView(@NonNull SplashScreenView view) { Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "SplashScreenView#createSurfaceView"); final Context viewContext = view.getContext(); final SurfaceView surfaceView = new SurfaceView(viewContext); surfaceView.setPadding(0, 0, 0, 0); Loading Loading @@ -361,6 +377,7 @@ public final class SplashScreenView extends FrameLayout { view.addView(surfaceView); view.mSurfaceView = surfaceView; Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); return surfaceView; } } Loading Loading @@ -532,23 +549,32 @@ public final class SplashScreenView extends FrameLayout { private void releaseAnimationSurfaceHost() { if (mSurfaceHost != null && !mIsCopied) { final SurfaceControlViewHost finalSurfaceHost = mSurfaceHost; mSurfaceHost = null; finalSurfaceHost.getView().post(() -> { if (DEBUG) { Log.d(TAG, "Shell removed splash screen." + " Releasing SurfaceControlViewHost on thread #" + Thread.currentThread().getId()); } finalSurfaceHost.release(); }); releaseIconHost(mSurfaceHost); mSurfaceHost = null; } else if (mSurfacePackage != null && mSurfaceHost == null) { mSurfacePackage = null; mClientCallback.sendResult(null); } } /** * Release the host which hold the SurfaceView of the icon. * @hide */ public static void releaseIconHost(SurfaceControlViewHost host) { final Drawable background = host.getView().getBackground(); if (background instanceof SplashScreenView.IconAnimateListener) { ((SplashScreenView.IconAnimateListener) background).stopAnimation(); } host.release(); } /** * Called when this view is attached to an activity. This also makes SystemUI colors * transparent so the content of splash screen view can draw fully. Loading Loading @@ -640,6 +666,11 @@ public final class SplashScreenView extends FrameLayout { * @return true if this drawable object can also be animated and it can be played now. */ boolean prepareAnimate(long duration, Runnable startListener); /** * Stop animation. */ void stopAnimation(); } /** Loading
libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java +17 −6 Original line number Diff line number Diff line Loading @@ -138,12 +138,14 @@ public class SplashscreenContentDrawer { * null if failed. */ void createContentView(Context context, @StartingWindowType int suggestType, ActivityInfo info, int taskId, Consumer<SplashScreenView> splashScreenViewConsumer) { int taskId, Consumer<SplashScreenView> splashScreenViewConsumer, Consumer<Runnable> uiThreadInitConsumer) { mSplashscreenWorkerHandler.post(() -> { SplashScreenView contentView; try { Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "makeSplashScreenContentView"); contentView = makeSplashScreenContentView(context, info, suggestType); contentView = makeSplashScreenContentView(context, info, suggestType, uiThreadInitConsumer); Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); } catch (RuntimeException e) { Slog.w(TAG, "failed creating starting window content at taskId: " Loading Loading @@ -239,7 +241,7 @@ public class SplashscreenContentDrawer { } private SplashScreenView makeSplashScreenContentView(Context context, ActivityInfo ai, @StartingWindowType int suggestType) { @StartingWindowType int suggestType, Consumer<Runnable> uiThreadInitConsumer) { updateDensity(); getWindowAttrs(context, mTmpAttrs); Loading @@ -254,6 +256,7 @@ public class SplashscreenContentDrawer { .setWindowBGColor(themeBGColor) .overlayDrawable(legacyDrawable) .chooseStyle(suggestType) .setUiThreadInitConsumer(uiThreadInitConsumer) .build(); } Loading Loading @@ -324,6 +327,7 @@ public class SplashscreenContentDrawer { private int mThemeColor; private Drawable[] mFinalIconDrawables; private int mFinalIconSize = mIconSize; private Consumer<Runnable> mUiThreadInitTask; StartingWindowViewBuilder(@NonNull Context context, @NonNull ActivityInfo aInfo) { mContext = context; Loading @@ -345,6 +349,11 @@ public class SplashscreenContentDrawer { return this; } StartingWindowViewBuilder setUiThreadInitConsumer(Consumer<Runnable> uiThreadInitTask) { mUiThreadInitTask = uiThreadInitTask; return this; } SplashScreenView build() { Drawable iconDrawable; final int animationDuration; Loading Loading @@ -391,7 +400,8 @@ public class SplashscreenContentDrawer { animationDuration = 0; } return fillViewWithIcon(mFinalIconSize, mFinalIconDrawables, animationDuration); return fillViewWithIcon(mFinalIconSize, mFinalIconDrawables, animationDuration, mUiThreadInitTask); } private class ShapeIconFactory extends BaseIconFactory { Loading Loading @@ -469,7 +479,7 @@ public class SplashscreenContentDrawer { } private SplashScreenView fillViewWithIcon(int iconSize, @Nullable Drawable[] iconDrawable, int animationDuration) { int animationDuration, Consumer<Runnable> uiThreadInitTask) { Drawable foreground = null; Drawable background = null; if (iconDrawable != null) { Loading @@ -485,7 +495,8 @@ public class SplashscreenContentDrawer { .setIconSize(iconSize) .setIconBackground(background) .setCenterViewDrawable(foreground) .setAnimationDurationMillis(animationDuration); .setAnimationDurationMillis(animationDuration) .setUiThreadInitConsumer(uiThreadInitTask); if (mSuggestType == STARTING_WINDOW_TYPE_SPLASH_SCREEN && mTmpAttrs.mBrandingImage != null) { Loading
libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java +7 −0 Original line number Diff line number Diff line Loading @@ -304,6 +304,13 @@ public class SplashscreenIconDrawableFactory { return true; } @Override public void stopAnimation() { if (mIconAnimator != null) { mIconAnimator.end(); } } private final Callback mCallback = new Callback() { @Override public void invalidateDrawable(@NonNull Drawable who) { Loading
libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java +13 −2 Original line number Diff line number Diff line Loading @@ -332,7 +332,7 @@ public class StartingSurfaceDrawer { mSysuiProxy.requestTopUi(true, TAG); } mSplashscreenContentDrawer.createContentView(context, suggestType, activityInfo, taskId, viewSupplier::setView); viewSupplier::setView, viewSupplier::setUiThreadInitTask); try { if (addWindow(taskId, appToken, rootLayout, display, params, suggestType)) { // We use the splash screen worker thread to create SplashScreenView while adding Loading Loading @@ -367,6 +367,7 @@ public class StartingSurfaceDrawer { private static class SplashScreenViewSupplier implements Supplier<SplashScreenView> { private SplashScreenView mView; private boolean mIsViewSet; private Runnable mUiThreadInitTask; void setView(SplashScreenView view) { synchronized (this) { mView = view; Loading @@ -375,6 +376,12 @@ public class StartingSurfaceDrawer { } } void setUiThreadInitTask(Runnable initTask) { synchronized (this) { mUiThreadInitTask = initTask; } } @Override public @Nullable SplashScreenView get() { synchronized (this) { Loading @@ -384,6 +391,10 @@ public class StartingSurfaceDrawer { } catch (InterruptedException ignored) { } } if (mUiThreadInitTask != null) { mUiThreadInitTask.run(); mUiThreadInitTask = null; } return mView; } } Loading Loading @@ -506,7 +517,7 @@ public class StartingSurfaceDrawer { Slog.v(TAG, reason + "the splash screen. Releasing SurfaceControlViewHost for task:" + taskId); } viewHost.getView().post(viewHost::release); SplashScreenView.releaseIconHost(viewHost); } protected boolean addWindow(int taskId, IBinder appToken, View view, Display display, Loading