Loading core/java/android/window/SplashScreenView.java +18 −1 Original line number Original line Diff line number Diff line Loading @@ -133,6 +133,8 @@ public final class SplashScreenView extends FrameLayout { private @ColorInt int mIconBackground; private @ColorInt int mIconBackground; private Bitmap mParceledIconBitmap; private Bitmap mParceledIconBitmap; private Drawable mIconDrawable; private Drawable mIconDrawable; // It is only set for legacy splash screen which won't be sent across processes. private Drawable mOverlayDrawable; private SurfaceControlViewHost.SurfacePackage mSurfacePackage; private SurfaceControlViewHost.SurfacePackage mSurfacePackage; private RemoteCallback mClientCallback; private RemoteCallback mClientCallback; private int mBrandingImageWidth; private int mBrandingImageWidth; Loading Loading @@ -192,6 +194,14 @@ public final class SplashScreenView extends FrameLayout { return this; return this; } } /** * Set the Drawable object to fill entire view */ public Builder setOverlayDrawable(@Nullable Drawable drawable) { mOverlayDrawable = drawable; return this; } /** /** * Set the Drawable object to fill the center view. * Set the Drawable object to fill the center view. */ */ Loading Loading @@ -236,7 +246,11 @@ public final class SplashScreenView extends FrameLayout { layoutInflater.inflate(R.layout.splash_screen_view, null, false); layoutInflater.inflate(R.layout.splash_screen_view, null, false); view.mInitBackgroundColor = mBackgroundColor; view.mInitBackgroundColor = mBackgroundColor; view.mInitIconBackgroundColor = mIconBackground; view.mInitIconBackgroundColor = mIconBackground; if (mOverlayDrawable != null) { view.setBackground(mOverlayDrawable); } else { view.setBackgroundColor(mBackgroundColor); view.setBackgroundColor(mBackgroundColor); } view.mClientCallback = mClientCallback; view.mClientCallback = mClientCallback; view.mBrandingImageView = view.findViewById(R.id.splashscreen_branding_view); view.mBrandingImageView = view.findViewById(R.id.splashscreen_branding_view); Loading @@ -261,6 +275,9 @@ public final class SplashScreenView extends FrameLayout { } } } } } } if (mOverlayDrawable != null || mIconDrawable == null) { view.setNotCopyable(); } if (mParceledIconBitmap != null) { if (mParceledIconBitmap != null) { view.mParceledIconBitmap = mParceledIconBitmap; view.mParceledIconBitmap = mParceledIconBitmap; Loading core/java/android/window/StartingWindowInfo.java +12 −2 Original line number Original line Diff line number Diff line Loading @@ -55,6 +55,9 @@ public final class StartingWindowInfo implements Parcelable { */ */ public static final int STARTING_WINDOW_TYPE_EMPTY_SPLASH_SCREEN = 3; public static final int STARTING_WINDOW_TYPE_EMPTY_SPLASH_SCREEN = 3; /** @hide **/ public static final int STARTING_WINDOW_TYPE_LEGACY_SPLASH_SCREEN = 4; /** /** * @hide * @hide */ */ Loading @@ -62,7 +65,8 @@ public final class StartingWindowInfo implements Parcelable { STARTING_WINDOW_TYPE_NONE, STARTING_WINDOW_TYPE_NONE, STARTING_WINDOW_TYPE_SPLASH_SCREEN, STARTING_WINDOW_TYPE_SPLASH_SCREEN, STARTING_WINDOW_TYPE_SNAPSHOT, STARTING_WINDOW_TYPE_SNAPSHOT, STARTING_WINDOW_TYPE_EMPTY_SPLASH_SCREEN STARTING_WINDOW_TYPE_EMPTY_SPLASH_SCREEN, STARTING_WINDOW_TYPE_LEGACY_SPLASH_SCREEN }) }) public @interface StartingWindowType {} public @interface StartingWindowType {} Loading Loading @@ -103,7 +107,8 @@ public final class StartingWindowInfo implements Parcelable { TYPE_PARAMETER_PROCESS_RUNNING, TYPE_PARAMETER_PROCESS_RUNNING, TYPE_PARAMETER_ALLOW_TASK_SNAPSHOT, TYPE_PARAMETER_ALLOW_TASK_SNAPSHOT, TYPE_PARAMETER_ACTIVITY_CREATED, TYPE_PARAMETER_ACTIVITY_CREATED, TYPE_PARAMETER_USE_EMPTY_SPLASH_SCREEN TYPE_PARAMETER_USE_EMPTY_SPLASH_SCREEN, TYPE_PARAMETER_LEGACY_SPLASH_SCREEN }) }) public @interface StartingTypeParams {} public @interface StartingTypeParams {} Loading @@ -122,6 +127,11 @@ public final class StartingWindowInfo implements Parcelable { public static final int TYPE_PARAMETER_ACTIVITY_CREATED = 0x00000010; public static final int TYPE_PARAMETER_ACTIVITY_CREATED = 0x00000010; /** @hide */ /** @hide */ public static final int TYPE_PARAMETER_USE_EMPTY_SPLASH_SCREEN = 0x00000020; public static final int TYPE_PARAMETER_USE_EMPTY_SPLASH_SCREEN = 0x00000020; /** * Application is allowed to use the legacy splash screen * @hide */ public static final int TYPE_PARAMETER_LEGACY_SPLASH_SCREEN = 0x80000000; /** /** * The parameters which effect the starting window type. * The parameters which effect the starting window type. Loading libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java +66 −28 Original line number Original line Diff line number Diff line Loading @@ -18,6 +18,9 @@ package com.android.wm.shell.startingsurface; import static android.os.Process.THREAD_PRIORITY_TOP_APP_BOOST; import static android.os.Process.THREAD_PRIORITY_TOP_APP_BOOST; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_EMPTY_SPLASH_SCREEN; import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_LEGACY_SPLASH_SCREEN; import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_SPLASH_SCREEN; import android.annotation.ColorInt; import android.annotation.ColorInt; import android.annotation.NonNull; import android.annotation.NonNull; Loading Loading @@ -47,6 +50,7 @@ import android.util.Slog; import android.view.SurfaceControl; import android.view.SurfaceControl; import android.view.View; import android.view.View; import android.window.SplashScreenView; import android.window.SplashScreenView; import android.window.StartingWindowInfo.StartingWindowType; import com.android.internal.R; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting; Loading Loading @@ -122,17 +126,17 @@ public class SplashscreenContentDrawer { * view on background thread so the view and the drawable can be create and pre-draw in * view on background thread so the view and the drawable can be create and pre-draw in * parallel. * parallel. * * * @param emptyView Create a splash screen view without icon on it. * @param suggestType Suggest type to create the splash screen view. * @param consumer Receiving the SplashScreenView object, which will also be executed * @param consumer Receiving the SplashScreenView object, which will also be executed * on splash screen thread. Note that the view can be null if failed. * on splash screen thread. Note that the view can be null if failed. */ */ void createContentView(Context context, boolean emptyView, ActivityInfo info, int taskId, void createContentView(Context context, @StartingWindowType int suggestType, ActivityInfo info, Consumer<SplashScreenView> consumer) { int taskId, Consumer<SplashScreenView> consumer) { mSplashscreenWorkerHandler.post(() -> { mSplashscreenWorkerHandler.post(() -> { SplashScreenView contentView; SplashScreenView contentView; try { try { Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "makeSplashScreenContentView"); Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "makeSplashScreenContentView"); contentView = makeSplashScreenContentView(context, info, emptyView); contentView = makeSplashScreenContentView(context, info, suggestType); Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); } catch (RuntimeException e) { } catch (RuntimeException e) { Slog.w(TAG, "failed creating starting window content at taskId: " Slog.w(TAG, "failed creating starting window content at taskId: " Loading Loading @@ -199,22 +203,45 @@ public class SplashscreenContentDrawer { } } } } private static Drawable peekLegacySplashscreenContent(Context context, SplashScreenWindowAttrs attrs) { final TypedArray a = context.obtainStyledAttributes(R.styleable.Window); final int resId = safeReturnAttrDefault((def) -> a.getResourceId(R.styleable.Window_windowSplashscreenContent, def), 0); a.recycle(); if (resId != 0) { return context.getDrawable(resId); } if (attrs.mWindowBgResId != 0) { return context.getDrawable(attrs.mWindowBgResId); } return null; } private SplashScreenView makeSplashScreenContentView(Context context, ActivityInfo ai, private SplashScreenView makeSplashScreenContentView(Context context, ActivityInfo ai, boolean emptyView) { @StartingWindowType int suggestType) { updateDensity(); updateDensity(); getWindowAttrs(context, mTmpAttrs); getWindowAttrs(context, mTmpAttrs); mLastPackageContextConfigHash = context.getResources().getConfiguration().hashCode(); mLastPackageContextConfigHash = context.getResources().getConfiguration().hashCode(); final int themeBGColor = mColorCache.getWindowColor(ai.packageName, mLastPackageContextConfigHash, mTmpAttrs.mWindowBgColor, mTmpAttrs.mWindowBgResId, final Drawable legacyDrawable = suggestType == STARTING_WINDOW_TYPE_LEGACY_SPLASH_SCREEN () -> peekWindowBGColor(context, mTmpAttrs)).mBgColor; ? peekLegacySplashscreenContent(context, mTmpAttrs) : null; // TODO (b/173975965) Tracking the performance on improved splash screen. final int themeBGColor = legacyDrawable != null ? getBGColorFromCache(ai, () -> estimateWindowBGColor(legacyDrawable)) : getBGColorFromCache(ai, () -> peekWindowBGColor(context, mTmpAttrs)); return new StartingWindowViewBuilder(context, ai) return new StartingWindowViewBuilder(context, ai) .setWindowBGColor(themeBGColor) .setWindowBGColor(themeBGColor) .makeEmptyView(emptyView) .overlayDrawable(legacyDrawable) .chooseStyle(suggestType) .build(); .build(); } } private int getBGColorFromCache(ActivityInfo ai, IntSupplier windowBgColorSupplier) { return mColorCache.getWindowColor(ai.packageName, mLastPackageContextConfigHash, mTmpAttrs.mWindowBgColor, mTmpAttrs.mWindowBgResId, windowBgColorSupplier).mBgColor; } private static <T> T safeReturnAttrDefault(UnaryOperator<T> getMethod, T def) { private static <T> T safeReturnAttrDefault(UnaryOperator<T> getMethod, T def) { try { try { return getMethod.apply(def); return getMethod.apply(def); Loading Loading @@ -267,7 +294,8 @@ public class SplashscreenContentDrawer { private final Context mContext; private final Context mContext; private final ActivityInfo mActivityInfo; private final ActivityInfo mActivityInfo; private boolean mEmptyView; private Drawable mOverlayDrawable; private int mSuggestType; private int mThemeColor; private int mThemeColor; private Drawable mFinalIconDrawable; private Drawable mFinalIconDrawable; private int mFinalIconSize = mIconSize; private int mFinalIconSize = mIconSize; Loading @@ -282,16 +310,22 @@ public class SplashscreenContentDrawer { return this; return this; } } StartingWindowViewBuilder makeEmptyView(boolean empty) { StartingWindowViewBuilder overlayDrawable(Drawable overlay) { mEmptyView = empty; mOverlayDrawable = overlay; return this; } StartingWindowViewBuilder chooseStyle(int suggestType) { mSuggestType = suggestType; return this; return this; } } SplashScreenView build() { SplashScreenView build() { Drawable iconDrawable; Drawable iconDrawable; final int animationDuration; final int animationDuration; if (mEmptyView) { if (mSuggestType == STARTING_WINDOW_TYPE_EMPTY_SPLASH_SCREEN // empty splash screen case || mSuggestType == STARTING_WINDOW_TYPE_LEGACY_SPLASH_SCREEN) { // empty or legacy splash screen case animationDuration = 0; animationDuration = 0; mFinalIconSize = 0; mFinalIconSize = 0; } else if (mTmpAttrs.mSplashScreenIcon != null) { } else if (mTmpAttrs.mSplashScreenIcon != null) { Loading Loading @@ -403,13 +437,15 @@ public class SplashscreenContentDrawer { Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "fillViewWithIcon"); Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "fillViewWithIcon"); final SplashScreenView.Builder builder = new SplashScreenView.Builder(mContext); final SplashScreenView.Builder builder = new SplashScreenView.Builder(mContext); builder.setBackgroundColor(mThemeColor); builder.setBackgroundColor(mThemeColor); builder.setOverlayDrawable(mOverlayDrawable); if (iconDrawable != null) { if (iconDrawable != null) { builder.setIconSize(iconSize) builder.setIconSize(iconSize) .setIconBackground(mTmpAttrs.mIconBgColor) .setIconBackground(mTmpAttrs.mIconBgColor) .setCenterViewDrawable(iconDrawable) .setCenterViewDrawable(iconDrawable) .setAnimationDurationMillis(animationDuration); .setAnimationDurationMillis(animationDuration); } } if (mTmpAttrs.mBrandingImage != null) { if (mSuggestType == STARTING_WINDOW_TYPE_SPLASH_SCREEN && mTmpAttrs.mBrandingImage != null) { builder.setBrandingDrawable(mTmpAttrs.mBrandingImage, mBrandingImageWidth, builder.setBrandingDrawable(mTmpAttrs.mBrandingImage, mBrandingImageWidth, mBrandingImageHeight); mBrandingImageHeight); } } Loading @@ -417,13 +453,13 @@ public class SplashscreenContentDrawer { if (DEBUG) { if (DEBUG) { Slog.d(TAG, "fillViewWithIcon surfaceWindowView " + splashScreenView); Slog.d(TAG, "fillViewWithIcon surfaceWindowView " + splashScreenView); } } if (mEmptyView) { if (mSuggestType != STARTING_WINDOW_TYPE_LEGACY_SPLASH_SCREEN) { splashScreenView.setNotCopyable(); splashScreenView.addOnAttachStateChangeListener( } new View.OnAttachStateChangeListener() { splashScreenView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() { @Override @Override public void onViewAttachedToWindow(View v) { public void onViewAttachedToWindow(View v) { SplashScreenView.applySystemBarsContrastColor(v.getWindowInsetsController(), SplashScreenView.applySystemBarsContrastColor( v.getWindowInsetsController(), splashScreenView.getInitBackgroundColor()); splashScreenView.getInitBackgroundColor()); } } Loading @@ -431,6 +467,8 @@ public class SplashscreenContentDrawer { public void onViewDetachedFromWindow(View v) { public void onViewDetachedFromWindow(View v) { } } }); }); } Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); return splashScreenView; return splashScreenView; } } Loading libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java +47 −21 Original line number Original line Diff line number Diff line Loading @@ -20,6 +20,8 @@ import static android.content.Context.CONTEXT_RESTRICTED; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static android.view.Choreographer.CALLBACK_INSETS_ANIMATION; import static android.view.Choreographer.CALLBACK_INSETS_ANIMATION; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.DEFAULT_DISPLAY; import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_LEGACY_SPLASH_SCREEN; import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_SNAPSHOT; import android.annotation.Nullable; import android.annotation.Nullable; import android.app.ActivityManager.RunningTaskInfo; import android.app.ActivityManager.RunningTaskInfo; Loading @@ -32,7 +34,6 @@ import android.content.res.Resources; import android.content.res.TypedArray; import android.content.res.TypedArray; import android.graphics.PixelFormat; import android.graphics.PixelFormat; import android.graphics.Rect; import android.graphics.Rect; import android.graphics.drawable.ColorDrawable; import android.hardware.display.DisplayManager; import android.hardware.display.DisplayManager; import android.os.IBinder; import android.os.IBinder; import android.os.RemoteCallback; import android.os.RemoteCallback; Loading @@ -50,6 +51,7 @@ import android.widget.FrameLayout; import android.window.SplashScreenView; import android.window.SplashScreenView; import android.window.SplashScreenView.SplashScreenViewParcelable; import android.window.SplashScreenView.SplashScreenViewParcelable; import android.window.StartingWindowInfo; import android.window.StartingWindowInfo; import android.window.StartingWindowInfo.StartingWindowType; import android.window.TaskSnapshot; import android.window.TaskSnapshot; import com.android.internal.R; import com.android.internal.R; Loading Loading @@ -149,10 +151,11 @@ public class StartingSurfaceDrawer { /** /** * Called when a task need a splash screen starting window. * Called when a task need a splash screen starting window. * @param emptyView Whether drawing an empty frame without anything on it. * * @param suggestType The suggestion type to draw the splash screen. */ */ void addSplashScreenStartingWindow(StartingWindowInfo windowInfo, IBinder appToken, void addSplashScreenStartingWindow(StartingWindowInfo windowInfo, IBinder appToken, boolean emptyView) { @StartingWindowType int suggestType) { final RunningTaskInfo taskInfo = windowInfo.taskInfo; final RunningTaskInfo taskInfo = windowInfo.taskInfo; final ActivityInfo activityInfo = taskInfo.topActivityInfo; final ActivityInfo activityInfo = taskInfo.topActivityInfo; if (activityInfo == null) { if (activityInfo == null) { Loading @@ -173,7 +176,8 @@ public class StartingSurfaceDrawer { : com.android.internal.R.style.Theme_DeviceDefault_DayNight; : com.android.internal.R.style.Theme_DeviceDefault_DayNight; if (DEBUG_SPLASH_SCREEN) { if (DEBUG_SPLASH_SCREEN) { Slog.d(TAG, "addSplashScreen " + activityInfo.packageName Slog.d(TAG, "addSplashScreen " + activityInfo.packageName + " theme=" + Integer.toHexString(theme) + " task= " + taskInfo.taskId); + " theme=" + Integer.toHexString(theme) + " task=" + taskInfo.taskId + " suggestType=" + suggestType); } } // Obtain proper context to launch on the right display. // Obtain proper context to launch on the right display. Loading Loading @@ -231,13 +235,19 @@ public class StartingSurfaceDrawer { params.setFitInsetsTypes(0); params.setFitInsetsTypes(0); params.format = PixelFormat.TRANSLUCENT; params.format = PixelFormat.TRANSLUCENT; int windowFlags = WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED int windowFlags = WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED | WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR; | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR; final TypedArray a = context.obtainStyledAttributes(R.styleable.Window); final TypedArray a = context.obtainStyledAttributes(R.styleable.Window); if (a.getBoolean(R.styleable.Window_windowShowWallpaper, false)) { if (a.getBoolean(R.styleable.Window_windowShowWallpaper, false)) { windowFlags |= WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; windowFlags |= WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; } } if (suggestType == STARTING_WINDOW_TYPE_LEGACY_SPLASH_SCREEN) { if (a.getBoolean(R.styleable.Window_windowDrawsSystemBarBackgrounds, false)) { windowFlags |= WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS; } } else { windowFlags |= WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS; } params.layoutInDisplayCutoutMode = a.getInt( params.layoutInDisplayCutoutMode = a.getInt( R.styleable.Window_windowLayoutInDisplayCutoutMode, R.styleable.Window_windowLayoutInDisplayCutoutMode, params.layoutInDisplayCutoutMode); params.layoutInDisplayCutoutMode); Loading Loading @@ -311,12 +321,12 @@ public class StartingSurfaceDrawer { } } Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); }; }; mSplashscreenContentDrawer.createContentView(context, emptyView, activityInfo, taskId, mSplashscreenContentDrawer.createContentView(context, suggestType, activityInfo, taskId, viewSupplier::setView); viewSupplier::setView); try { try { final WindowManager wm = context.getSystemService(WindowManager.class); final WindowManager wm = context.getSystemService(WindowManager.class); if (addWindow(taskId, appToken, rootLayout, wm, params)) { if (addWindow(taskId, appToken, rootLayout, wm, params, suggestType)) { // We use the splash screen worker thread to create SplashScreenView while adding // We use the splash screen worker thread to create SplashScreenView while adding // the window, as otherwise Choreographer#doFrame might be delayed on this thread. // the window, as otherwise Choreographer#doFrame might be delayed on this thread. // And since Choreographer#doFrame won't happen immediately after adding the window, // And since Choreographer#doFrame won't happen immediately after adding the window, Loading @@ -336,8 +346,10 @@ public class StartingSurfaceDrawer { int getStartingWindowBackgroundColorForTask(int taskId) { int getStartingWindowBackgroundColorForTask(int taskId) { StartingWindowRecord startingWindowRecord = mStartingWindowRecords.get(taskId); StartingWindowRecord startingWindowRecord = mStartingWindowRecords.get(taskId); if (startingWindowRecord == null || startingWindowRecord.mContentView == null) return 0; if (startingWindowRecord == null || startingWindowRecord.mContentView == null) { return ((ColorDrawable) startingWindowRecord.mContentView.getBackground()).getColor(); return 0; } return startingWindowRecord.mContentView.getInitBackgroundColor(); } } private static class SplashScreenViewSupplier implements Supplier<SplashScreenView> { private static class SplashScreenViewSupplier implements Supplier<SplashScreenView> { Loading Loading @@ -379,7 +391,7 @@ public class StartingSurfaceDrawer { return; return; } } final StartingWindowRecord tView = new StartingWindowRecord(appToken, final StartingWindowRecord tView = new StartingWindowRecord(appToken, null/* decorView */, surface); null/* decorView */, surface, STARTING_WINDOW_TYPE_SNAPSHOT); mStartingWindowRecords.put(taskId, tView); mStartingWindowRecords.put(taskId, tView); } } Loading Loading @@ -449,7 +461,7 @@ public class StartingSurfaceDrawer { } } protected boolean addWindow(int taskId, IBinder appToken, View view, WindowManager wm, protected boolean addWindow(int taskId, IBinder appToken, View view, WindowManager wm, WindowManager.LayoutParams params) { WindowManager.LayoutParams params, @StartingWindowType int suggestType) { boolean shouldSaveView = true; boolean shouldSaveView = true; try { try { Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "addRootView"); Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "addRootView"); Loading @@ -469,14 +481,15 @@ public class StartingSurfaceDrawer { } } if (shouldSaveView) { if (shouldSaveView) { removeWindowNoAnimate(taskId); removeWindowNoAnimate(taskId); saveSplashScreenRecord(appToken, taskId, view); saveSplashScreenRecord(appToken, taskId, view, suggestType); } } return shouldSaveView; return shouldSaveView; } } private void saveSplashScreenRecord(IBinder appToken, int taskId, View view) { private void saveSplashScreenRecord(IBinder appToken, int taskId, View view, @StartingWindowType int suggestType) { final StartingWindowRecord tView = new StartingWindowRecord(appToken, view, final StartingWindowRecord tView = new StartingWindowRecord(appToken, view, null/* TaskSnapshotWindow */); null/* TaskSnapshotWindow */, suggestType); mStartingWindowRecords.put(taskId, tView); mStartingWindowRecords.put(taskId, tView); } } Loading @@ -493,6 +506,9 @@ public class StartingSurfaceDrawer { Slog.v(TAG, "Removing splash screen window for task: " + taskId); Slog.v(TAG, "Removing splash screen window for task: " + taskId); } } if (record.mContentView != null) { if (record.mContentView != null) { if (record.mSuggestType == STARTING_WINDOW_TYPE_LEGACY_SPLASH_SCREEN) { removeWindowInner(record.mDecorView, false); } else { if (playRevealAnimation) { if (playRevealAnimation) { mSplashscreenContentDrawer.applyExitAnimation(record.mContentView, mSplashscreenContentDrawer.applyExitAnimation(record.mContentView, leash, frame, leash, frame, Loading @@ -502,6 +518,7 @@ public class StartingSurfaceDrawer { // default exit animation // default exit animation removeWindowInner(record.mDecorView, true); removeWindowInner(record.mDecorView, true); } } } } else { } else { // shouldn't happen // shouldn't happen Slog.e(TAG, "Found empty splash screen, remove!"); Slog.e(TAG, "Found empty splash screen, remove!"); Loading Loading @@ -537,6 +554,7 @@ public class StartingSurfaceDrawer { private final TaskSnapshotWindow mTaskSnapshotWindow; private final TaskSnapshotWindow mTaskSnapshotWindow; private SplashScreenView mContentView; private SplashScreenView mContentView; private boolean mSetSplashScreen; private boolean mSetSplashScreen; private @StartingWindowType int mSuggestType; StartingWindowRecord(IBinder appToken, View decorView, StartingWindowRecord(IBinder appToken, View decorView, TaskSnapshotWindow taskSnapshotWindow) { TaskSnapshotWindow taskSnapshotWindow) { Loading @@ -545,6 +563,14 @@ public class StartingSurfaceDrawer { mTaskSnapshotWindow = taskSnapshotWindow; mTaskSnapshotWindow = taskSnapshotWindow; } } StartingWindowRecord(IBinder appToken, View decorView, TaskSnapshotWindow taskSnapshotWindow, @StartingWindowType int suggestType) { mAppToken = appToken; mDecorView = decorView; mTaskSnapshotWindow = taskSnapshotWindow; mSuggestType = suggestType; } private void setSplashScreenView(SplashScreenView splashScreenView) { private void setSplashScreenView(SplashScreenView splashScreenView) { if (mSetSplashScreen) { if (mSetSplashScreen) { return; return; Loading libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java +11 −10 Original line number Original line Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.wm.shell.startingsurface; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_EMPTY_SPLASH_SCREEN; import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_EMPTY_SPLASH_SCREEN; import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_LEGACY_SPLASH_SCREEN; import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_SNAPSHOT; import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_SNAPSHOT; import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_SPLASH_SCREEN; import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_SPLASH_SCREEN; Loading @@ -31,6 +32,7 @@ import android.os.Trace; import android.util.Slog; import android.util.Slog; import android.view.SurfaceControl; import android.view.SurfaceControl; import android.window.StartingWindowInfo; import android.window.StartingWindowInfo; import android.window.StartingWindowInfo.StartingWindowType; import android.window.TaskOrganizer; import android.window.TaskOrganizer; import android.window.TaskSnapshot; import android.window.TaskSnapshot; Loading Loading @@ -106,10 +108,6 @@ public class StartingWindowController implements RemoteCallable<StartingWindowCo mTaskLaunchingCallback = listener; mTaskLaunchingCallback = listener; } } private boolean shouldSendToListener(int suggestionType) { return suggestionType != STARTING_WINDOW_TYPE_EMPTY_SPLASH_SCREEN; } /** /** * Called when a task need a starting window. * Called when a task need a starting window. */ */ Loading @@ -120,12 +118,9 @@ public class StartingWindowController implements RemoteCallable<StartingWindowCo final int suggestionType = mStartingWindowTypeAlgorithm.getSuggestedWindowType( final int suggestionType = mStartingWindowTypeAlgorithm.getSuggestedWindowType( windowInfo); windowInfo); final RunningTaskInfo runningTaskInfo = windowInfo.taskInfo; final RunningTaskInfo runningTaskInfo = windowInfo.taskInfo; if (suggestionType == STARTING_WINDOW_TYPE_SPLASH_SCREEN) { if (isSplashScreenType(suggestionType)) { mStartingSurfaceDrawer.addSplashScreenStartingWindow(windowInfo, appToken, false /* emptyView */); } else if (suggestionType == STARTING_WINDOW_TYPE_EMPTY_SPLASH_SCREEN) { mStartingSurfaceDrawer.addSplashScreenStartingWindow(windowInfo, appToken, mStartingSurfaceDrawer.addSplashScreenStartingWindow(windowInfo, appToken, true /* emptyView */); suggestionType); } else if (suggestionType == STARTING_WINDOW_TYPE_SNAPSHOT) { } else if (suggestionType == STARTING_WINDOW_TYPE_SNAPSHOT) { final TaskSnapshot snapshot = windowInfo.mTaskSnapshot; final TaskSnapshot snapshot = windowInfo.mTaskSnapshot; mStartingSurfaceDrawer.makeTaskSnapshotWindow(windowInfo, appToken, mStartingSurfaceDrawer.makeTaskSnapshotWindow(windowInfo, appToken, Loading @@ -133,7 +128,7 @@ public class StartingWindowController implements RemoteCallable<StartingWindowCo } else /* suggestionType == STARTING_WINDOW_TYPE_NONE */ { } else /* suggestionType == STARTING_WINDOW_TYPE_NONE */ { // Don't add a staring window. // Don't add a staring window. } } if (mTaskLaunchingCallback != null && shouldSendToListener(suggestionType)) { if (mTaskLaunchingCallback != null && isSplashScreenType(suggestionType)) { int taskId = runningTaskInfo.taskId; int taskId = runningTaskInfo.taskId; int color = mStartingSurfaceDrawer.getStartingWindowBackgroundColorForTask(taskId); int color = mStartingSurfaceDrawer.getStartingWindowBackgroundColorForTask(taskId); mTaskLaunchingCallback.accept(taskId, suggestionType, color); mTaskLaunchingCallback.accept(taskId, suggestionType, color); Loading @@ -143,6 +138,12 @@ public class StartingWindowController implements RemoteCallable<StartingWindowCo }); }); } } private static boolean isSplashScreenType(@StartingWindowType int suggestionType) { return suggestionType == STARTING_WINDOW_TYPE_SPLASH_SCREEN || suggestionType == STARTING_WINDOW_TYPE_EMPTY_SPLASH_SCREEN || suggestionType == STARTING_WINDOW_TYPE_LEGACY_SPLASH_SCREEN; } public void copySplashScreenView(int taskId) { public void copySplashScreenView(int taskId) { mSplashScreenExecutor.execute(() -> { mSplashScreenExecutor.execute(() -> { mStartingSurfaceDrawer.copySplashScreenView(taskId); mStartingSurfaceDrawer.copySplashScreenView(taskId); Loading Loading
core/java/android/window/SplashScreenView.java +18 −1 Original line number Original line Diff line number Diff line Loading @@ -133,6 +133,8 @@ public final class SplashScreenView extends FrameLayout { private @ColorInt int mIconBackground; private @ColorInt int mIconBackground; private Bitmap mParceledIconBitmap; private Bitmap mParceledIconBitmap; private Drawable mIconDrawable; private Drawable mIconDrawable; // It is only set for legacy splash screen which won't be sent across processes. private Drawable mOverlayDrawable; private SurfaceControlViewHost.SurfacePackage mSurfacePackage; private SurfaceControlViewHost.SurfacePackage mSurfacePackage; private RemoteCallback mClientCallback; private RemoteCallback mClientCallback; private int mBrandingImageWidth; private int mBrandingImageWidth; Loading Loading @@ -192,6 +194,14 @@ public final class SplashScreenView extends FrameLayout { return this; return this; } } /** * Set the Drawable object to fill entire view */ public Builder setOverlayDrawable(@Nullable Drawable drawable) { mOverlayDrawable = drawable; return this; } /** /** * Set the Drawable object to fill the center view. * Set the Drawable object to fill the center view. */ */ Loading Loading @@ -236,7 +246,11 @@ public final class SplashScreenView extends FrameLayout { layoutInflater.inflate(R.layout.splash_screen_view, null, false); layoutInflater.inflate(R.layout.splash_screen_view, null, false); view.mInitBackgroundColor = mBackgroundColor; view.mInitBackgroundColor = mBackgroundColor; view.mInitIconBackgroundColor = mIconBackground; view.mInitIconBackgroundColor = mIconBackground; if (mOverlayDrawable != null) { view.setBackground(mOverlayDrawable); } else { view.setBackgroundColor(mBackgroundColor); view.setBackgroundColor(mBackgroundColor); } view.mClientCallback = mClientCallback; view.mClientCallback = mClientCallback; view.mBrandingImageView = view.findViewById(R.id.splashscreen_branding_view); view.mBrandingImageView = view.findViewById(R.id.splashscreen_branding_view); Loading @@ -261,6 +275,9 @@ public final class SplashScreenView extends FrameLayout { } } } } } } if (mOverlayDrawable != null || mIconDrawable == null) { view.setNotCopyable(); } if (mParceledIconBitmap != null) { if (mParceledIconBitmap != null) { view.mParceledIconBitmap = mParceledIconBitmap; view.mParceledIconBitmap = mParceledIconBitmap; Loading
core/java/android/window/StartingWindowInfo.java +12 −2 Original line number Original line Diff line number Diff line Loading @@ -55,6 +55,9 @@ public final class StartingWindowInfo implements Parcelable { */ */ public static final int STARTING_WINDOW_TYPE_EMPTY_SPLASH_SCREEN = 3; public static final int STARTING_WINDOW_TYPE_EMPTY_SPLASH_SCREEN = 3; /** @hide **/ public static final int STARTING_WINDOW_TYPE_LEGACY_SPLASH_SCREEN = 4; /** /** * @hide * @hide */ */ Loading @@ -62,7 +65,8 @@ public final class StartingWindowInfo implements Parcelable { STARTING_WINDOW_TYPE_NONE, STARTING_WINDOW_TYPE_NONE, STARTING_WINDOW_TYPE_SPLASH_SCREEN, STARTING_WINDOW_TYPE_SPLASH_SCREEN, STARTING_WINDOW_TYPE_SNAPSHOT, STARTING_WINDOW_TYPE_SNAPSHOT, STARTING_WINDOW_TYPE_EMPTY_SPLASH_SCREEN STARTING_WINDOW_TYPE_EMPTY_SPLASH_SCREEN, STARTING_WINDOW_TYPE_LEGACY_SPLASH_SCREEN }) }) public @interface StartingWindowType {} public @interface StartingWindowType {} Loading Loading @@ -103,7 +107,8 @@ public final class StartingWindowInfo implements Parcelable { TYPE_PARAMETER_PROCESS_RUNNING, TYPE_PARAMETER_PROCESS_RUNNING, TYPE_PARAMETER_ALLOW_TASK_SNAPSHOT, TYPE_PARAMETER_ALLOW_TASK_SNAPSHOT, TYPE_PARAMETER_ACTIVITY_CREATED, TYPE_PARAMETER_ACTIVITY_CREATED, TYPE_PARAMETER_USE_EMPTY_SPLASH_SCREEN TYPE_PARAMETER_USE_EMPTY_SPLASH_SCREEN, TYPE_PARAMETER_LEGACY_SPLASH_SCREEN }) }) public @interface StartingTypeParams {} public @interface StartingTypeParams {} Loading @@ -122,6 +127,11 @@ public final class StartingWindowInfo implements Parcelable { public static final int TYPE_PARAMETER_ACTIVITY_CREATED = 0x00000010; public static final int TYPE_PARAMETER_ACTIVITY_CREATED = 0x00000010; /** @hide */ /** @hide */ public static final int TYPE_PARAMETER_USE_EMPTY_SPLASH_SCREEN = 0x00000020; public static final int TYPE_PARAMETER_USE_EMPTY_SPLASH_SCREEN = 0x00000020; /** * Application is allowed to use the legacy splash screen * @hide */ public static final int TYPE_PARAMETER_LEGACY_SPLASH_SCREEN = 0x80000000; /** /** * The parameters which effect the starting window type. * The parameters which effect the starting window type. Loading
libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java +66 −28 Original line number Original line Diff line number Diff line Loading @@ -18,6 +18,9 @@ package com.android.wm.shell.startingsurface; import static android.os.Process.THREAD_PRIORITY_TOP_APP_BOOST; import static android.os.Process.THREAD_PRIORITY_TOP_APP_BOOST; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_EMPTY_SPLASH_SCREEN; import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_LEGACY_SPLASH_SCREEN; import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_SPLASH_SCREEN; import android.annotation.ColorInt; import android.annotation.ColorInt; import android.annotation.NonNull; import android.annotation.NonNull; Loading Loading @@ -47,6 +50,7 @@ import android.util.Slog; import android.view.SurfaceControl; import android.view.SurfaceControl; import android.view.View; import android.view.View; import android.window.SplashScreenView; import android.window.SplashScreenView; import android.window.StartingWindowInfo.StartingWindowType; import com.android.internal.R; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting; Loading Loading @@ -122,17 +126,17 @@ public class SplashscreenContentDrawer { * view on background thread so the view and the drawable can be create and pre-draw in * view on background thread so the view and the drawable can be create and pre-draw in * parallel. * parallel. * * * @param emptyView Create a splash screen view without icon on it. * @param suggestType Suggest type to create the splash screen view. * @param consumer Receiving the SplashScreenView object, which will also be executed * @param consumer Receiving the SplashScreenView object, which will also be executed * on splash screen thread. Note that the view can be null if failed. * on splash screen thread. Note that the view can be null if failed. */ */ void createContentView(Context context, boolean emptyView, ActivityInfo info, int taskId, void createContentView(Context context, @StartingWindowType int suggestType, ActivityInfo info, Consumer<SplashScreenView> consumer) { int taskId, Consumer<SplashScreenView> consumer) { mSplashscreenWorkerHandler.post(() -> { mSplashscreenWorkerHandler.post(() -> { SplashScreenView contentView; SplashScreenView contentView; try { try { Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "makeSplashScreenContentView"); Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "makeSplashScreenContentView"); contentView = makeSplashScreenContentView(context, info, emptyView); contentView = makeSplashScreenContentView(context, info, suggestType); Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); } catch (RuntimeException e) { } catch (RuntimeException e) { Slog.w(TAG, "failed creating starting window content at taskId: " Slog.w(TAG, "failed creating starting window content at taskId: " Loading Loading @@ -199,22 +203,45 @@ public class SplashscreenContentDrawer { } } } } private static Drawable peekLegacySplashscreenContent(Context context, SplashScreenWindowAttrs attrs) { final TypedArray a = context.obtainStyledAttributes(R.styleable.Window); final int resId = safeReturnAttrDefault((def) -> a.getResourceId(R.styleable.Window_windowSplashscreenContent, def), 0); a.recycle(); if (resId != 0) { return context.getDrawable(resId); } if (attrs.mWindowBgResId != 0) { return context.getDrawable(attrs.mWindowBgResId); } return null; } private SplashScreenView makeSplashScreenContentView(Context context, ActivityInfo ai, private SplashScreenView makeSplashScreenContentView(Context context, ActivityInfo ai, boolean emptyView) { @StartingWindowType int suggestType) { updateDensity(); updateDensity(); getWindowAttrs(context, mTmpAttrs); getWindowAttrs(context, mTmpAttrs); mLastPackageContextConfigHash = context.getResources().getConfiguration().hashCode(); mLastPackageContextConfigHash = context.getResources().getConfiguration().hashCode(); final int themeBGColor = mColorCache.getWindowColor(ai.packageName, mLastPackageContextConfigHash, mTmpAttrs.mWindowBgColor, mTmpAttrs.mWindowBgResId, final Drawable legacyDrawable = suggestType == STARTING_WINDOW_TYPE_LEGACY_SPLASH_SCREEN () -> peekWindowBGColor(context, mTmpAttrs)).mBgColor; ? peekLegacySplashscreenContent(context, mTmpAttrs) : null; // TODO (b/173975965) Tracking the performance on improved splash screen. final int themeBGColor = legacyDrawable != null ? getBGColorFromCache(ai, () -> estimateWindowBGColor(legacyDrawable)) : getBGColorFromCache(ai, () -> peekWindowBGColor(context, mTmpAttrs)); return new StartingWindowViewBuilder(context, ai) return new StartingWindowViewBuilder(context, ai) .setWindowBGColor(themeBGColor) .setWindowBGColor(themeBGColor) .makeEmptyView(emptyView) .overlayDrawable(legacyDrawable) .chooseStyle(suggestType) .build(); .build(); } } private int getBGColorFromCache(ActivityInfo ai, IntSupplier windowBgColorSupplier) { return mColorCache.getWindowColor(ai.packageName, mLastPackageContextConfigHash, mTmpAttrs.mWindowBgColor, mTmpAttrs.mWindowBgResId, windowBgColorSupplier).mBgColor; } private static <T> T safeReturnAttrDefault(UnaryOperator<T> getMethod, T def) { private static <T> T safeReturnAttrDefault(UnaryOperator<T> getMethod, T def) { try { try { return getMethod.apply(def); return getMethod.apply(def); Loading Loading @@ -267,7 +294,8 @@ public class SplashscreenContentDrawer { private final Context mContext; private final Context mContext; private final ActivityInfo mActivityInfo; private final ActivityInfo mActivityInfo; private boolean mEmptyView; private Drawable mOverlayDrawable; private int mSuggestType; private int mThemeColor; private int mThemeColor; private Drawable mFinalIconDrawable; private Drawable mFinalIconDrawable; private int mFinalIconSize = mIconSize; private int mFinalIconSize = mIconSize; Loading @@ -282,16 +310,22 @@ public class SplashscreenContentDrawer { return this; return this; } } StartingWindowViewBuilder makeEmptyView(boolean empty) { StartingWindowViewBuilder overlayDrawable(Drawable overlay) { mEmptyView = empty; mOverlayDrawable = overlay; return this; } StartingWindowViewBuilder chooseStyle(int suggestType) { mSuggestType = suggestType; return this; return this; } } SplashScreenView build() { SplashScreenView build() { Drawable iconDrawable; Drawable iconDrawable; final int animationDuration; final int animationDuration; if (mEmptyView) { if (mSuggestType == STARTING_WINDOW_TYPE_EMPTY_SPLASH_SCREEN // empty splash screen case || mSuggestType == STARTING_WINDOW_TYPE_LEGACY_SPLASH_SCREEN) { // empty or legacy splash screen case animationDuration = 0; animationDuration = 0; mFinalIconSize = 0; mFinalIconSize = 0; } else if (mTmpAttrs.mSplashScreenIcon != null) { } else if (mTmpAttrs.mSplashScreenIcon != null) { Loading Loading @@ -403,13 +437,15 @@ public class SplashscreenContentDrawer { Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "fillViewWithIcon"); Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "fillViewWithIcon"); final SplashScreenView.Builder builder = new SplashScreenView.Builder(mContext); final SplashScreenView.Builder builder = new SplashScreenView.Builder(mContext); builder.setBackgroundColor(mThemeColor); builder.setBackgroundColor(mThemeColor); builder.setOverlayDrawable(mOverlayDrawable); if (iconDrawable != null) { if (iconDrawable != null) { builder.setIconSize(iconSize) builder.setIconSize(iconSize) .setIconBackground(mTmpAttrs.mIconBgColor) .setIconBackground(mTmpAttrs.mIconBgColor) .setCenterViewDrawable(iconDrawable) .setCenterViewDrawable(iconDrawable) .setAnimationDurationMillis(animationDuration); .setAnimationDurationMillis(animationDuration); } } if (mTmpAttrs.mBrandingImage != null) { if (mSuggestType == STARTING_WINDOW_TYPE_SPLASH_SCREEN && mTmpAttrs.mBrandingImage != null) { builder.setBrandingDrawable(mTmpAttrs.mBrandingImage, mBrandingImageWidth, builder.setBrandingDrawable(mTmpAttrs.mBrandingImage, mBrandingImageWidth, mBrandingImageHeight); mBrandingImageHeight); } } Loading @@ -417,13 +453,13 @@ public class SplashscreenContentDrawer { if (DEBUG) { if (DEBUG) { Slog.d(TAG, "fillViewWithIcon surfaceWindowView " + splashScreenView); Slog.d(TAG, "fillViewWithIcon surfaceWindowView " + splashScreenView); } } if (mEmptyView) { if (mSuggestType != STARTING_WINDOW_TYPE_LEGACY_SPLASH_SCREEN) { splashScreenView.setNotCopyable(); splashScreenView.addOnAttachStateChangeListener( } new View.OnAttachStateChangeListener() { splashScreenView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() { @Override @Override public void onViewAttachedToWindow(View v) { public void onViewAttachedToWindow(View v) { SplashScreenView.applySystemBarsContrastColor(v.getWindowInsetsController(), SplashScreenView.applySystemBarsContrastColor( v.getWindowInsetsController(), splashScreenView.getInitBackgroundColor()); splashScreenView.getInitBackgroundColor()); } } Loading @@ -431,6 +467,8 @@ public class SplashscreenContentDrawer { public void onViewDetachedFromWindow(View v) { public void onViewDetachedFromWindow(View v) { } } }); }); } Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); return splashScreenView; return splashScreenView; } } Loading
libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java +47 −21 Original line number Original line Diff line number Diff line Loading @@ -20,6 +20,8 @@ import static android.content.Context.CONTEXT_RESTRICTED; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static android.view.Choreographer.CALLBACK_INSETS_ANIMATION; import static android.view.Choreographer.CALLBACK_INSETS_ANIMATION; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.DEFAULT_DISPLAY; import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_LEGACY_SPLASH_SCREEN; import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_SNAPSHOT; import android.annotation.Nullable; import android.annotation.Nullable; import android.app.ActivityManager.RunningTaskInfo; import android.app.ActivityManager.RunningTaskInfo; Loading @@ -32,7 +34,6 @@ import android.content.res.Resources; import android.content.res.TypedArray; import android.content.res.TypedArray; import android.graphics.PixelFormat; import android.graphics.PixelFormat; import android.graphics.Rect; import android.graphics.Rect; import android.graphics.drawable.ColorDrawable; import android.hardware.display.DisplayManager; import android.hardware.display.DisplayManager; import android.os.IBinder; import android.os.IBinder; import android.os.RemoteCallback; import android.os.RemoteCallback; Loading @@ -50,6 +51,7 @@ import android.widget.FrameLayout; import android.window.SplashScreenView; import android.window.SplashScreenView; import android.window.SplashScreenView.SplashScreenViewParcelable; import android.window.SplashScreenView.SplashScreenViewParcelable; import android.window.StartingWindowInfo; import android.window.StartingWindowInfo; import android.window.StartingWindowInfo.StartingWindowType; import android.window.TaskSnapshot; import android.window.TaskSnapshot; import com.android.internal.R; import com.android.internal.R; Loading Loading @@ -149,10 +151,11 @@ public class StartingSurfaceDrawer { /** /** * Called when a task need a splash screen starting window. * Called when a task need a splash screen starting window. * @param emptyView Whether drawing an empty frame without anything on it. * * @param suggestType The suggestion type to draw the splash screen. */ */ void addSplashScreenStartingWindow(StartingWindowInfo windowInfo, IBinder appToken, void addSplashScreenStartingWindow(StartingWindowInfo windowInfo, IBinder appToken, boolean emptyView) { @StartingWindowType int suggestType) { final RunningTaskInfo taskInfo = windowInfo.taskInfo; final RunningTaskInfo taskInfo = windowInfo.taskInfo; final ActivityInfo activityInfo = taskInfo.topActivityInfo; final ActivityInfo activityInfo = taskInfo.topActivityInfo; if (activityInfo == null) { if (activityInfo == null) { Loading @@ -173,7 +176,8 @@ public class StartingSurfaceDrawer { : com.android.internal.R.style.Theme_DeviceDefault_DayNight; : com.android.internal.R.style.Theme_DeviceDefault_DayNight; if (DEBUG_SPLASH_SCREEN) { if (DEBUG_SPLASH_SCREEN) { Slog.d(TAG, "addSplashScreen " + activityInfo.packageName Slog.d(TAG, "addSplashScreen " + activityInfo.packageName + " theme=" + Integer.toHexString(theme) + " task= " + taskInfo.taskId); + " theme=" + Integer.toHexString(theme) + " task=" + taskInfo.taskId + " suggestType=" + suggestType); } } // Obtain proper context to launch on the right display. // Obtain proper context to launch on the right display. Loading Loading @@ -231,13 +235,19 @@ public class StartingSurfaceDrawer { params.setFitInsetsTypes(0); params.setFitInsetsTypes(0); params.format = PixelFormat.TRANSLUCENT; params.format = PixelFormat.TRANSLUCENT; int windowFlags = WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED int windowFlags = WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED | WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR; | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR; final TypedArray a = context.obtainStyledAttributes(R.styleable.Window); final TypedArray a = context.obtainStyledAttributes(R.styleable.Window); if (a.getBoolean(R.styleable.Window_windowShowWallpaper, false)) { if (a.getBoolean(R.styleable.Window_windowShowWallpaper, false)) { windowFlags |= WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; windowFlags |= WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; } } if (suggestType == STARTING_WINDOW_TYPE_LEGACY_SPLASH_SCREEN) { if (a.getBoolean(R.styleable.Window_windowDrawsSystemBarBackgrounds, false)) { windowFlags |= WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS; } } else { windowFlags |= WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS; } params.layoutInDisplayCutoutMode = a.getInt( params.layoutInDisplayCutoutMode = a.getInt( R.styleable.Window_windowLayoutInDisplayCutoutMode, R.styleable.Window_windowLayoutInDisplayCutoutMode, params.layoutInDisplayCutoutMode); params.layoutInDisplayCutoutMode); Loading Loading @@ -311,12 +321,12 @@ public class StartingSurfaceDrawer { } } Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); }; }; mSplashscreenContentDrawer.createContentView(context, emptyView, activityInfo, taskId, mSplashscreenContentDrawer.createContentView(context, suggestType, activityInfo, taskId, viewSupplier::setView); viewSupplier::setView); try { try { final WindowManager wm = context.getSystemService(WindowManager.class); final WindowManager wm = context.getSystemService(WindowManager.class); if (addWindow(taskId, appToken, rootLayout, wm, params)) { if (addWindow(taskId, appToken, rootLayout, wm, params, suggestType)) { // We use the splash screen worker thread to create SplashScreenView while adding // We use the splash screen worker thread to create SplashScreenView while adding // the window, as otherwise Choreographer#doFrame might be delayed on this thread. // the window, as otherwise Choreographer#doFrame might be delayed on this thread. // And since Choreographer#doFrame won't happen immediately after adding the window, // And since Choreographer#doFrame won't happen immediately after adding the window, Loading @@ -336,8 +346,10 @@ public class StartingSurfaceDrawer { int getStartingWindowBackgroundColorForTask(int taskId) { int getStartingWindowBackgroundColorForTask(int taskId) { StartingWindowRecord startingWindowRecord = mStartingWindowRecords.get(taskId); StartingWindowRecord startingWindowRecord = mStartingWindowRecords.get(taskId); if (startingWindowRecord == null || startingWindowRecord.mContentView == null) return 0; if (startingWindowRecord == null || startingWindowRecord.mContentView == null) { return ((ColorDrawable) startingWindowRecord.mContentView.getBackground()).getColor(); return 0; } return startingWindowRecord.mContentView.getInitBackgroundColor(); } } private static class SplashScreenViewSupplier implements Supplier<SplashScreenView> { private static class SplashScreenViewSupplier implements Supplier<SplashScreenView> { Loading Loading @@ -379,7 +391,7 @@ public class StartingSurfaceDrawer { return; return; } } final StartingWindowRecord tView = new StartingWindowRecord(appToken, final StartingWindowRecord tView = new StartingWindowRecord(appToken, null/* decorView */, surface); null/* decorView */, surface, STARTING_WINDOW_TYPE_SNAPSHOT); mStartingWindowRecords.put(taskId, tView); mStartingWindowRecords.put(taskId, tView); } } Loading Loading @@ -449,7 +461,7 @@ public class StartingSurfaceDrawer { } } protected boolean addWindow(int taskId, IBinder appToken, View view, WindowManager wm, protected boolean addWindow(int taskId, IBinder appToken, View view, WindowManager wm, WindowManager.LayoutParams params) { WindowManager.LayoutParams params, @StartingWindowType int suggestType) { boolean shouldSaveView = true; boolean shouldSaveView = true; try { try { Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "addRootView"); Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "addRootView"); Loading @@ -469,14 +481,15 @@ public class StartingSurfaceDrawer { } } if (shouldSaveView) { if (shouldSaveView) { removeWindowNoAnimate(taskId); removeWindowNoAnimate(taskId); saveSplashScreenRecord(appToken, taskId, view); saveSplashScreenRecord(appToken, taskId, view, suggestType); } } return shouldSaveView; return shouldSaveView; } } private void saveSplashScreenRecord(IBinder appToken, int taskId, View view) { private void saveSplashScreenRecord(IBinder appToken, int taskId, View view, @StartingWindowType int suggestType) { final StartingWindowRecord tView = new StartingWindowRecord(appToken, view, final StartingWindowRecord tView = new StartingWindowRecord(appToken, view, null/* TaskSnapshotWindow */); null/* TaskSnapshotWindow */, suggestType); mStartingWindowRecords.put(taskId, tView); mStartingWindowRecords.put(taskId, tView); } } Loading @@ -493,6 +506,9 @@ public class StartingSurfaceDrawer { Slog.v(TAG, "Removing splash screen window for task: " + taskId); Slog.v(TAG, "Removing splash screen window for task: " + taskId); } } if (record.mContentView != null) { if (record.mContentView != null) { if (record.mSuggestType == STARTING_WINDOW_TYPE_LEGACY_SPLASH_SCREEN) { removeWindowInner(record.mDecorView, false); } else { if (playRevealAnimation) { if (playRevealAnimation) { mSplashscreenContentDrawer.applyExitAnimation(record.mContentView, mSplashscreenContentDrawer.applyExitAnimation(record.mContentView, leash, frame, leash, frame, Loading @@ -502,6 +518,7 @@ public class StartingSurfaceDrawer { // default exit animation // default exit animation removeWindowInner(record.mDecorView, true); removeWindowInner(record.mDecorView, true); } } } } else { } else { // shouldn't happen // shouldn't happen Slog.e(TAG, "Found empty splash screen, remove!"); Slog.e(TAG, "Found empty splash screen, remove!"); Loading Loading @@ -537,6 +554,7 @@ public class StartingSurfaceDrawer { private final TaskSnapshotWindow mTaskSnapshotWindow; private final TaskSnapshotWindow mTaskSnapshotWindow; private SplashScreenView mContentView; private SplashScreenView mContentView; private boolean mSetSplashScreen; private boolean mSetSplashScreen; private @StartingWindowType int mSuggestType; StartingWindowRecord(IBinder appToken, View decorView, StartingWindowRecord(IBinder appToken, View decorView, TaskSnapshotWindow taskSnapshotWindow) { TaskSnapshotWindow taskSnapshotWindow) { Loading @@ -545,6 +563,14 @@ public class StartingSurfaceDrawer { mTaskSnapshotWindow = taskSnapshotWindow; mTaskSnapshotWindow = taskSnapshotWindow; } } StartingWindowRecord(IBinder appToken, View decorView, TaskSnapshotWindow taskSnapshotWindow, @StartingWindowType int suggestType) { mAppToken = appToken; mDecorView = decorView; mTaskSnapshotWindow = taskSnapshotWindow; mSuggestType = suggestType; } private void setSplashScreenView(SplashScreenView splashScreenView) { private void setSplashScreenView(SplashScreenView splashScreenView) { if (mSetSplashScreen) { if (mSetSplashScreen) { return; return; Loading
libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java +11 −10 Original line number Original line Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.wm.shell.startingsurface; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_EMPTY_SPLASH_SCREEN; import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_EMPTY_SPLASH_SCREEN; import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_LEGACY_SPLASH_SCREEN; import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_SNAPSHOT; import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_SNAPSHOT; import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_SPLASH_SCREEN; import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_SPLASH_SCREEN; Loading @@ -31,6 +32,7 @@ import android.os.Trace; import android.util.Slog; import android.util.Slog; import android.view.SurfaceControl; import android.view.SurfaceControl; import android.window.StartingWindowInfo; import android.window.StartingWindowInfo; import android.window.StartingWindowInfo.StartingWindowType; import android.window.TaskOrganizer; import android.window.TaskOrganizer; import android.window.TaskSnapshot; import android.window.TaskSnapshot; Loading Loading @@ -106,10 +108,6 @@ public class StartingWindowController implements RemoteCallable<StartingWindowCo mTaskLaunchingCallback = listener; mTaskLaunchingCallback = listener; } } private boolean shouldSendToListener(int suggestionType) { return suggestionType != STARTING_WINDOW_TYPE_EMPTY_SPLASH_SCREEN; } /** /** * Called when a task need a starting window. * Called when a task need a starting window. */ */ Loading @@ -120,12 +118,9 @@ public class StartingWindowController implements RemoteCallable<StartingWindowCo final int suggestionType = mStartingWindowTypeAlgorithm.getSuggestedWindowType( final int suggestionType = mStartingWindowTypeAlgorithm.getSuggestedWindowType( windowInfo); windowInfo); final RunningTaskInfo runningTaskInfo = windowInfo.taskInfo; final RunningTaskInfo runningTaskInfo = windowInfo.taskInfo; if (suggestionType == STARTING_WINDOW_TYPE_SPLASH_SCREEN) { if (isSplashScreenType(suggestionType)) { mStartingSurfaceDrawer.addSplashScreenStartingWindow(windowInfo, appToken, false /* emptyView */); } else if (suggestionType == STARTING_WINDOW_TYPE_EMPTY_SPLASH_SCREEN) { mStartingSurfaceDrawer.addSplashScreenStartingWindow(windowInfo, appToken, mStartingSurfaceDrawer.addSplashScreenStartingWindow(windowInfo, appToken, true /* emptyView */); suggestionType); } else if (suggestionType == STARTING_WINDOW_TYPE_SNAPSHOT) { } else if (suggestionType == STARTING_WINDOW_TYPE_SNAPSHOT) { final TaskSnapshot snapshot = windowInfo.mTaskSnapshot; final TaskSnapshot snapshot = windowInfo.mTaskSnapshot; mStartingSurfaceDrawer.makeTaskSnapshotWindow(windowInfo, appToken, mStartingSurfaceDrawer.makeTaskSnapshotWindow(windowInfo, appToken, Loading @@ -133,7 +128,7 @@ public class StartingWindowController implements RemoteCallable<StartingWindowCo } else /* suggestionType == STARTING_WINDOW_TYPE_NONE */ { } else /* suggestionType == STARTING_WINDOW_TYPE_NONE */ { // Don't add a staring window. // Don't add a staring window. } } if (mTaskLaunchingCallback != null && shouldSendToListener(suggestionType)) { if (mTaskLaunchingCallback != null && isSplashScreenType(suggestionType)) { int taskId = runningTaskInfo.taskId; int taskId = runningTaskInfo.taskId; int color = mStartingSurfaceDrawer.getStartingWindowBackgroundColorForTask(taskId); int color = mStartingSurfaceDrawer.getStartingWindowBackgroundColorForTask(taskId); mTaskLaunchingCallback.accept(taskId, suggestionType, color); mTaskLaunchingCallback.accept(taskId, suggestionType, color); Loading @@ -143,6 +138,12 @@ public class StartingWindowController implements RemoteCallable<StartingWindowCo }); }); } } private static boolean isSplashScreenType(@StartingWindowType int suggestionType) { return suggestionType == STARTING_WINDOW_TYPE_SPLASH_SCREEN || suggestionType == STARTING_WINDOW_TYPE_EMPTY_SPLASH_SCREEN || suggestionType == STARTING_WINDOW_TYPE_LEGACY_SPLASH_SCREEN; } public void copySplashScreenView(int taskId) { public void copySplashScreenView(int taskId) { mSplashScreenExecutor.execute(() -> { mSplashScreenExecutor.execute(() -> { mStartingSurfaceDrawer.copySplashScreenView(taskId); mStartingSurfaceDrawer.copySplashScreenView(taskId); Loading