Adding the SurfaceView on splash screen thread.
The SurfaceView of the AVD icon should be create on splash screen thread instead of worker thread, this can guarantee that the first frame of the FrameLayout and AVD will be draw at the same frame. And it also become faster by combining two view in same traversal together. Also stop the AVD animation after splash screen window removed. Bug: 195736516 Test: verify no more Choreographer#doFrame on splash screen thread after splash screen window removed. Change-Id: I5942db8974f1272d9c26ac19b164312e4424be66
This commit is contained in:
@@ -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>
|
||||
@@ -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;
|
||||
@@ -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.
|
||||
*/
|
||||
@@ -262,7 +273,11 @@ public final class SplashScreenView extends FrameLayout {
|
||||
// center icon
|
||||
if (mIconDrawable instanceof SplashScreenView.IconAnimateListener
|
||||
|| mSurfacePackage != null) {
|
||||
view.mIconView = createSurfaceView(view);
|
||||
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;
|
||||
@@ -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);
|
||||
@@ -361,6 +377,7 @@ public final class SplashScreenView extends FrameLayout {
|
||||
|
||||
view.addView(surfaceView);
|
||||
view.mSurfaceView = surfaceView;
|
||||
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
|
||||
return surfaceView;
|
||||
}
|
||||
}
|
||||
@@ -532,23 +549,32 @@ public final class SplashScreenView extends FrameLayout {
|
||||
|
||||
private void releaseAnimationSurfaceHost() {
|
||||
if (mSurfaceHost != null && !mIsCopied) {
|
||||
final SurfaceControlViewHost finalSurfaceHost = mSurfaceHost;
|
||||
if (DEBUG) {
|
||||
Log.d(TAG,
|
||||
"Shell removed splash screen."
|
||||
+ " Releasing SurfaceControlViewHost on thread #"
|
||||
+ Thread.currentThread().getId());
|
||||
}
|
||||
releaseIconHost(mSurfaceHost);
|
||||
mSurfaceHost = null;
|
||||
finalSurfaceHost.getView().post(() -> {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG,
|
||||
"Shell removed splash screen."
|
||||
+ " Releasing SurfaceControlViewHost on thread #"
|
||||
+ Thread.currentThread().getId());
|
||||
}
|
||||
finalSurfaceHost.release();
|
||||
});
|
||||
} 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.
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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: "
|
||||
@@ -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);
|
||||
@@ -254,6 +256,7 @@ public class SplashscreenContentDrawer {
|
||||
.setWindowBGColor(themeBGColor)
|
||||
.overlayDrawable(legacyDrawable)
|
||||
.chooseStyle(suggestType)
|
||||
.setUiThreadInitConsumer(uiThreadInitConsumer)
|
||||
.build();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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 {
|
||||
@@ -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) {
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
@@ -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;
|
||||
@@ -375,6 +376,12 @@ public class StartingSurfaceDrawer {
|
||||
}
|
||||
}
|
||||
|
||||
void setUiThreadInitTask(Runnable initTask) {
|
||||
synchronized (this) {
|
||||
mUiThreadInitTask = initTask;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable SplashScreenView get() {
|
||||
synchronized (this) {
|
||||
@@ -384,6 +391,10 @@ public class StartingSurfaceDrawer {
|
||||
} catch (InterruptedException ignored) {
|
||||
}
|
||||
}
|
||||
if (mUiThreadInitTask != null) {
|
||||
mUiThreadInitTask.run();
|
||||
mUiThreadInitTask = null;
|
||||
}
|
||||
return mView;
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user