diff --git a/core/java/android/window/SplashScreenView.java b/core/java/android/window/SplashScreenView.java index f04155d112d49..b90e628da7142 100644 --- a/core/java/android/window/SplashScreenView.java +++ b/core/java/android/window/SplashScreenView.java @@ -151,6 +151,7 @@ public final class SplashScreenView extends FrameLayout { private Instant mIconAnimationStart; private Duration mIconAnimationDuration; private Consumer mUiThreadInitTask; + private boolean mAllowHandleEmpty = true; public Builder(@NonNull Context context) { mContext = context; @@ -257,6 +258,15 @@ public final class SplashScreenView extends FrameLayout { return this; } + /** + * Sets whether this view can be copied and transferred to the client if the view is + * empty style splash screen. + */ + public Builder setAllowHandleEmpty(boolean allowHandleEmpty) { + mAllowHandleEmpty = allowHandleEmpty; + return this; + } + /** * Create SplashScreenWindowView object from materials. */ @@ -303,7 +313,7 @@ public final class SplashScreenView extends FrameLayout { } view.mIconView = imageView; } - if (mOverlayDrawable != null || mIconDrawable == null) { + if (mOverlayDrawable != null || (view.mIconView == null && !mAllowHandleEmpty)) { view.setNotCopyable(); } @@ -720,13 +730,15 @@ public final class SplashScreenView extends FrameLayout { private RemoteCallback mClientCallback; public SplashScreenViewParcelable(SplashScreenView view) { - mIconSize = view.mIconView.getWidth(); + final View iconView = view.getIconView(); + mIconSize = iconView != null ? iconView.getWidth() : 0; mBackgroundColor = view.getInitBackgroundColor(); - mIconBackground = copyDrawable(view.getIconView().getBackground()); + mIconBackground = iconView != null ? copyDrawable(iconView.getBackground()) : null; mSurfacePackage = view.mSurfacePackageCopy; if (mSurfacePackage == null) { // We only need to copy the drawable if we are not using a SurfaceView - mIconBitmap = copyDrawable(((ImageView) view.getIconView()).getDrawable()); + mIconBitmap = iconView != null + ? copyDrawable(((ImageView) view.getIconView()).getDrawable()) : null; } mBrandingBitmap = copyDrawable(view.getBrandingView().getBackground()); diff --git a/core/java/android/window/StartingWindowInfo.java b/core/java/android/window/StartingWindowInfo.java index aec910ba6f4b6..24899a4bcb9df 100644 --- a/core/java/android/window/StartingWindowInfo.java +++ b/core/java/android/window/StartingWindowInfo.java @@ -116,6 +116,7 @@ public final class StartingWindowInfo implements Parcelable { TYPE_PARAMETER_ALLOW_TASK_SNAPSHOT, TYPE_PARAMETER_ACTIVITY_CREATED, TYPE_PARAMETER_USE_EMPTY_SPLASH_SCREEN, + TYPE_PARAMETER_ALLOW_HANDLE_EMPTY_SCREEN, TYPE_PARAMETER_LEGACY_SPLASH_SCREEN }) public @interface StartingTypeParams {} @@ -140,6 +141,11 @@ public final class StartingWindowInfo implements Parcelable { * @hide */ public static final int TYPE_PARAMETER_ACTIVITY_DRAWN = 0x00000040; + /** + * Application is allowed to handle empty splash screen. + * @hide + */ + public static final int TYPE_PARAMETER_ALLOW_HANDLE_EMPTY_SCREEN = 0x00000080; /** * Application is allowed to use the legacy splash screen * @hide @@ -185,6 +191,13 @@ public final class StartingWindowInfo implements Parcelable { readFromParcel(source); } + /** + * Return whether the application allow to handle the empty style splash screen. + */ + public boolean allowHandleEmptySplashScreen() { + return (startingWindowTypeParameter & TYPE_PARAMETER_ALLOW_HANDLE_EMPTY_SCREEN) != 0; + } + @Override public int describeContents() { return 0; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java index 413627d1810fe..e255e44503fb3 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java @@ -54,6 +54,7 @@ import android.view.ContextThemeWrapper; import android.view.SurfaceControl; import android.view.View; import android.window.SplashScreenView; +import android.window.StartingWindowInfo; import android.window.StartingWindowInfo.StartingWindowType; import com.android.internal.R; @@ -138,8 +139,8 @@ public class SplashscreenContentDrawer { * executed on splash screen thread. Note that the view can be * null if failed. */ - void createContentView(Context context, @StartingWindowType int suggestType, ActivityInfo info, - int taskId, Consumer splashScreenViewConsumer, + void createContentView(Context context, @StartingWindowType int suggestType, + StartingWindowInfo info, Consumer splashScreenViewConsumer, Consumer uiThreadInitConsumer) { mSplashscreenWorkerHandler.post(() -> { SplashScreenView contentView; @@ -150,7 +151,7 @@ public class SplashscreenContentDrawer { Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); } catch (RuntimeException e) { Slog.w(TAG, "failed creating starting window content at taskId: " - + taskId, e); + + info.taskInfo.taskId, e); contentView = null; } splashScreenViewConsumer.accept(contentView); @@ -241,7 +242,7 @@ public class SplashscreenContentDrawer { return null; } - private SplashScreenView makeSplashScreenContentView(Context context, ActivityInfo ai, + private SplashScreenView makeSplashScreenContentView(Context context, StartingWindowInfo info, @StartingWindowType int suggestType, Consumer uiThreadInitConsumer) { updateDensity(); @@ -250,6 +251,9 @@ public class SplashscreenContentDrawer { final Drawable legacyDrawable = suggestType == STARTING_WINDOW_TYPE_LEGACY_SPLASH_SCREEN ? peekLegacySplashscreenContent(context, mTmpAttrs) : null; + final ActivityInfo ai = info.targetActivityInfo != null + ? info.targetActivityInfo + : info.taskInfo.topActivityInfo; final int themeBGColor = legacyDrawable != null ? getBGColorFromCache(ai, () -> estimateWindowBGColor(legacyDrawable)) : getBGColorFromCache(ai, () -> peekWindowBGColor(context, mTmpAttrs)); @@ -258,6 +262,7 @@ public class SplashscreenContentDrawer { .overlayDrawable(legacyDrawable) .chooseStyle(suggestType) .setUiThreadInitConsumer(uiThreadInitConsumer) + .setAllowHandleEmpty(info.allowHandleEmptySplashScreen()) .build(); } @@ -327,6 +332,7 @@ public class SplashscreenContentDrawer { private Drawable[] mFinalIconDrawables; private int mFinalIconSize = mIconSize; private Consumer mUiThreadInitTask; + private boolean mAllowHandleEmpty; StartingWindowViewBuilder(@NonNull Context context, @NonNull ActivityInfo aInfo) { mContext = context; @@ -353,6 +359,11 @@ public class SplashscreenContentDrawer { return this; } + StartingWindowViewBuilder setAllowHandleEmpty(boolean allowHandleEmpty) { + mAllowHandleEmpty = allowHandleEmpty; + return this; + } + SplashScreenView build() { Drawable iconDrawable; final int animationDuration; @@ -491,7 +502,8 @@ public class SplashscreenContentDrawer { .setIconBackground(background) .setCenterViewDrawable(foreground) .setAnimationDurationMillis(animationDuration) - .setUiThreadInitConsumer(uiThreadInitTask); + .setUiThreadInitConsumer(uiThreadInitTask) + .setAllowHandleEmpty(mAllowHandleEmpty); if (mSuggestType == STARTING_WINDOW_TYPE_SPLASH_SCREEN && mTmpAttrs.mBrandingImage != null) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java index f8902c6d2cc66..9a966b8f93053 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java @@ -328,7 +328,7 @@ public class StartingSurfaceDrawer { if (mSysuiProxy != null) { mSysuiProxy.requestTopUi(true, TAG); } - mSplashscreenContentDrawer.createContentView(context, suggestType, activityInfo, taskId, + mSplashscreenContentDrawer.createContentView(context, suggestType, windowInfo, viewSupplier::setView, viewSupplier::setUiThreadInitTask); try { if (addWindow(taskId, appToken, rootLayout, display, params, suggestType)) { diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 49d6a344419ff..897549b9cb5bf 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -395,9 +395,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // How many activities have to be scheduled to stop to force a stop pass. private static final int MAX_STOPPING_TO_FORCE = 3; - private static final int STARTING_WINDOW_TYPE_NONE = 0; - private static final int STARTING_WINDOW_TYPE_SNAPSHOT = 1; - private static final int STARTING_WINDOW_TYPE_SPLASH_SCREEN = 2; + static final int STARTING_WINDOW_TYPE_NONE = 0; + static final int STARTING_WINDOW_TYPE_SNAPSHOT = 1; + static final int STARTING_WINDOW_TYPE_SPLASH_SCREEN = 2; static final int INVALID_PID = -1; @@ -2149,7 +2149,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A final int typeParameter = StartingSurfaceController .makeStartingWindowTypeParameter(newTask, taskSwitch, processRunning, - allowTaskSnapshot, activityCreated, useEmpty, useLegacy, activityAllDrawn); + allowTaskSnapshot, activityCreated, useEmpty, useLegacy, activityAllDrawn, + type, packageName, mUserId); if (type == STARTING_WINDOW_TYPE_SNAPSHOT) { if (isActivityTypeHome()) { diff --git a/services/core/java/com/android/server/wm/StartingSurfaceController.java b/services/core/java/com/android/server/wm/StartingSurfaceController.java index eb73cd8072046..2a3767fe613af 100644 --- a/services/core/java/com/android/server/wm/StartingSurfaceController.java +++ b/services/core/java/com/android/server/wm/StartingSurfaceController.java @@ -18,6 +18,7 @@ package com.android.server.wm; import static android.window.StartingWindowInfo.TYPE_PARAMETER_ACTIVITY_CREATED; import static android.window.StartingWindowInfo.TYPE_PARAMETER_ACTIVITY_DRAWN; +import static android.window.StartingWindowInfo.TYPE_PARAMETER_ALLOW_HANDLE_EMPTY_SCREEN; import static android.window.StartingWindowInfo.TYPE_PARAMETER_ALLOW_TASK_SNAPSHOT; import static android.window.StartingWindowInfo.TYPE_PARAMETER_LEGACY_SPLASH_SCREEN; import static android.window.StartingWindowInfo.TYPE_PARAMETER_NEW_TASK; @@ -25,12 +26,17 @@ import static android.window.StartingWindowInfo.TYPE_PARAMETER_PROCESS_RUNNING; import static android.window.StartingWindowInfo.TYPE_PARAMETER_TASK_SWITCH; import static android.window.StartingWindowInfo.TYPE_PARAMETER_USE_EMPTY_SPLASH_SCREEN; +import static com.android.server.wm.ActivityRecord.STARTING_WINDOW_TYPE_SPLASH_SCREEN; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import android.annotation.NonNull; import android.annotation.Nullable; +import android.app.compat.CompatChanges; +import android.compat.annotation.ChangeId; +import android.compat.annotation.EnabledSince; import android.content.pm.ApplicationInfo; +import android.os.UserHandle; import android.util.Slog; import android.window.TaskSnapshot; @@ -43,6 +49,14 @@ import java.util.function.Supplier; public class StartingSurfaceController { private static final String TAG = TAG_WITH_CLASS_NAME ? StartingSurfaceController.class.getSimpleName() : TAG_WM; + /** + * Allow the empty style splash screen view can be copy and transfer to another process if + * the app targeting to {@link android.os.Build.VERSION_CODES#TIRAMISU} or higher. + */ + @ChangeId + @EnabledSince(targetSdkVersion = android.os.Build.VERSION_CODES.TIRAMISU) + private static final long ALLOW_COPY_EMPTY_VIEW = 205907456L; + private final WindowManagerService mService; private final SplashScreenExceptionList mSplashScreenExceptionsList; @@ -81,7 +95,8 @@ public class StartingSurfaceController { static int makeStartingWindowTypeParameter(boolean newTask, boolean taskSwitch, boolean processRunning, boolean allowTaskSnapshot, boolean activityCreated, - boolean useEmpty, boolean useLegacy, boolean activityDrawn) { + boolean useEmpty, boolean useLegacy, boolean activityDrawn, int startingWindowType, + String packageName, int userId) { int parameter = 0; if (newTask) { parameter |= TYPE_PARAMETER_NEW_TASK; @@ -107,6 +122,11 @@ public class StartingSurfaceController { if (activityDrawn) { parameter |= TYPE_PARAMETER_ACTIVITY_DRAWN; } + if (startingWindowType == STARTING_WINDOW_TYPE_SPLASH_SCREEN + && CompatChanges.isChangeEnabled(ALLOW_COPY_EMPTY_VIEW, packageName, + UserHandle.of(userId))) { + parameter |= TYPE_PARAMETER_ALLOW_HANDLE_EMPTY_SCREEN; + } return parameter; }