diff options
| author | 2021-07-05 15:35:01 +0000 | |
|---|---|---|
| committer | 2021-07-05 15:35:01 +0000 | |
| commit | 2be72d030be57907622bbf61af3b69b61d20d521 (patch) | |
| tree | be14175d8304e3a2fc811daea614e22aea8c254e | |
| parent | 52a1d139ae9a60561369f5b0b410a1d2c465f53f (diff) | |
| parent | f08dae31587a342b64057340ea6b27e61c48a7e5 (diff) | |
Merge "Implement the legacy splash screen behavior" into sc-dev
10 files changed, 243 insertions, 81 deletions
diff --git a/core/java/android/window/SplashScreenView.java b/core/java/android/window/SplashScreenView.java index 148986a558e7..1efd2e381289 100644 --- a/core/java/android/window/SplashScreenView.java +++ b/core/java/android/window/SplashScreenView.java @@ -133,6 +133,8 @@ public final class SplashScreenView extends FrameLayout { private @ColorInt int mIconBackground; private Bitmap mParceledIconBitmap; 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 RemoteCallback mClientCallback; private int mBrandingImageWidth; @@ -193,6 +195,14 @@ public final class SplashScreenView extends FrameLayout { } /** + * 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. */ public Builder setCenterViewDrawable(@Nullable Drawable drawable) { @@ -236,7 +246,11 @@ public final class SplashScreenView extends FrameLayout { layoutInflater.inflate(R.layout.splash_screen_view, null, false); view.mInitBackgroundColor = mBackgroundColor; view.mInitIconBackgroundColor = mIconBackground; - view.setBackgroundColor(mBackgroundColor); + if (mOverlayDrawable != null) { + view.setBackground(mOverlayDrawable); + } else { + view.setBackgroundColor(mBackgroundColor); + } view.mClientCallback = mClientCallback; view.mBrandingImageView = view.findViewById(R.id.splashscreen_branding_view); @@ -261,6 +275,9 @@ public final class SplashScreenView extends FrameLayout { } } } + if (mOverlayDrawable != null || mIconDrawable == null) { + view.setNotCopyable(); + } if (mParceledIconBitmap != null) { view.mParceledIconBitmap = mParceledIconBitmap; diff --git a/core/java/android/window/StartingWindowInfo.java b/core/java/android/window/StartingWindowInfo.java index 8bc2177b42e1..566f154fba3b 100644 --- a/core/java/android/window/StartingWindowInfo.java +++ b/core/java/android/window/StartingWindowInfo.java @@ -55,6 +55,9 @@ public final class StartingWindowInfo implements Parcelable { */ public static final int STARTING_WINDOW_TYPE_EMPTY_SPLASH_SCREEN = 3; + /** @hide **/ + public static final int STARTING_WINDOW_TYPE_LEGACY_SPLASH_SCREEN = 4; + /** * @hide */ @@ -62,7 +65,8 @@ public final class StartingWindowInfo implements Parcelable { STARTING_WINDOW_TYPE_NONE, STARTING_WINDOW_TYPE_SPLASH_SCREEN, 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 {} @@ -103,7 +107,8 @@ public final class StartingWindowInfo implements Parcelable { TYPE_PARAMETER_PROCESS_RUNNING, TYPE_PARAMETER_ALLOW_TASK_SNAPSHOT, TYPE_PARAMETER_ACTIVITY_CREATED, - TYPE_PARAMETER_USE_EMPTY_SPLASH_SCREEN + TYPE_PARAMETER_USE_EMPTY_SPLASH_SCREEN, + TYPE_PARAMETER_LEGACY_SPLASH_SCREEN }) public @interface StartingTypeParams {} @@ -122,6 +127,11 @@ public final class StartingWindowInfo implements Parcelable { public static final int TYPE_PARAMETER_ACTIVITY_CREATED = 0x00000010; /** @hide */ 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. 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 b09d0d89a6b9..75dd561ffc61 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 @@ -18,6 +18,9 @@ package com.android.wm.shell.startingsurface; import static android.os.Process.THREAD_PRIORITY_TOP_APP_BOOST; 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.NonNull; @@ -47,6 +50,7 @@ import android.util.Slog; import android.view.SurfaceControl; import android.view.View; import android.window.SplashScreenView; +import android.window.StartingWindowInfo.StartingWindowType; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; @@ -122,17 +126,17 @@ public class SplashscreenContentDrawer { * view on background thread so the view and the drawable can be create and pre-draw in * 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 * on splash screen thread. Note that the view can be null if failed. */ - void createContentView(Context context, boolean emptyView, ActivityInfo info, int taskId, - Consumer<SplashScreenView> consumer) { + void createContentView(Context context, @StartingWindowType int suggestType, ActivityInfo info, + int taskId, Consumer<SplashScreenView> consumer) { mSplashscreenWorkerHandler.post(() -> { SplashScreenView contentView; try { Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "makeSplashScreenContentView"); - contentView = makeSplashScreenContentView(context, info, emptyView); + contentView = makeSplashScreenContentView(context, info, suggestType); Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); } catch (RuntimeException e) { Slog.w(TAG, "failed creating starting window content at taskId: " @@ -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, - boolean emptyView) { + @StartingWindowType int suggestType) { updateDensity(); getWindowAttrs(context, mTmpAttrs); mLastPackageContextConfigHash = context.getResources().getConfiguration().hashCode(); - final int themeBGColor = mColorCache.getWindowColor(ai.packageName, - mLastPackageContextConfigHash, mTmpAttrs.mWindowBgColor, mTmpAttrs.mWindowBgResId, - () -> peekWindowBGColor(context, mTmpAttrs)).mBgColor; - // TODO (b/173975965) Tracking the performance on improved splash screen. + + final Drawable legacyDrawable = suggestType == STARTING_WINDOW_TYPE_LEGACY_SPLASH_SCREEN + ? peekLegacySplashscreenContent(context, mTmpAttrs) : null; + final int themeBGColor = legacyDrawable != null + ? getBGColorFromCache(ai, () -> estimateWindowBGColor(legacyDrawable)) + : getBGColorFromCache(ai, () -> peekWindowBGColor(context, mTmpAttrs)); return new StartingWindowViewBuilder(context, ai) .setWindowBGColor(themeBGColor) - .makeEmptyView(emptyView) + .overlayDrawable(legacyDrawable) + .chooseStyle(suggestType) .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) { try { return getMethod.apply(def); @@ -267,7 +294,8 @@ public class SplashscreenContentDrawer { private final Context mContext; private final ActivityInfo mActivityInfo; - private boolean mEmptyView; + private Drawable mOverlayDrawable; + private int mSuggestType; private int mThemeColor; private Drawable mFinalIconDrawable; private int mFinalIconSize = mIconSize; @@ -282,16 +310,22 @@ public class SplashscreenContentDrawer { return this; } - StartingWindowViewBuilder makeEmptyView(boolean empty) { - mEmptyView = empty; + StartingWindowViewBuilder overlayDrawable(Drawable overlay) { + mOverlayDrawable = overlay; + return this; + } + + StartingWindowViewBuilder chooseStyle(int suggestType) { + mSuggestType = suggestType; return this; } SplashScreenView build() { Drawable iconDrawable; final int animationDuration; - if (mEmptyView) { - // empty splash screen case + if (mSuggestType == STARTING_WINDOW_TYPE_EMPTY_SPLASH_SCREEN + || mSuggestType == STARTING_WINDOW_TYPE_LEGACY_SPLASH_SCREEN) { + // empty or legacy splash screen case animationDuration = 0; mFinalIconSize = 0; } else if (mTmpAttrs.mSplashScreenIcon != null) { @@ -403,13 +437,15 @@ public class SplashscreenContentDrawer { Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "fillViewWithIcon"); final SplashScreenView.Builder builder = new SplashScreenView.Builder(mContext); builder.setBackgroundColor(mThemeColor); + builder.setOverlayDrawable(mOverlayDrawable); if (iconDrawable != null) { builder.setIconSize(iconSize) .setIconBackground(mTmpAttrs.mIconBgColor) .setCenterViewDrawable(iconDrawable) .setAnimationDurationMillis(animationDuration); } - if (mTmpAttrs.mBrandingImage != null) { + if (mSuggestType == STARTING_WINDOW_TYPE_SPLASH_SCREEN + && mTmpAttrs.mBrandingImage != null) { builder.setBrandingDrawable(mTmpAttrs.mBrandingImage, mBrandingImageWidth, mBrandingImageHeight); } @@ -417,20 +453,22 @@ public class SplashscreenContentDrawer { if (DEBUG) { Slog.d(TAG, "fillViewWithIcon surfaceWindowView " + splashScreenView); } - if (mEmptyView) { - splashScreenView.setNotCopyable(); + if (mSuggestType != STARTING_WINDOW_TYPE_LEGACY_SPLASH_SCREEN) { + splashScreenView.addOnAttachStateChangeListener( + new View.OnAttachStateChangeListener() { + @Override + public void onViewAttachedToWindow(View v) { + SplashScreenView.applySystemBarsContrastColor( + v.getWindowInsetsController(), + splashScreenView.getInitBackgroundColor()); + } + + @Override + public void onViewDetachedFromWindow(View v) { + } + }); } - splashScreenView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() { - @Override - public void onViewAttachedToWindow(View v) { - SplashScreenView.applySystemBarsContrastColor(v.getWindowInsetsController(), - splashScreenView.getInitBackgroundColor()); - } - @Override - public void onViewDetachedFromWindow(View v) { - } - }); Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); return splashScreenView; } 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 670af963230a..3cbce9c38f12 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 @@ -20,6 +20,8 @@ import static android.content.Context.CONTEXT_RESTRICTED; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static android.view.Choreographer.CALLBACK_INSETS_ANIMATION; 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.app.ActivityManager.RunningTaskInfo; @@ -32,7 +34,6 @@ import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.PixelFormat; import android.graphics.Rect; -import android.graphics.drawable.ColorDrawable; import android.hardware.display.DisplayManager; import android.os.IBinder; import android.os.RemoteCallback; @@ -50,6 +51,7 @@ import android.widget.FrameLayout; import android.window.SplashScreenView; import android.window.SplashScreenView.SplashScreenViewParcelable; import android.window.StartingWindowInfo; +import android.window.StartingWindowInfo.StartingWindowType; import android.window.TaskSnapshot; import com.android.internal.R; @@ -149,10 +151,11 @@ public class StartingSurfaceDrawer { /** * 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, - boolean emptyView) { + @StartingWindowType int suggestType) { final RunningTaskInfo taskInfo = windowInfo.taskInfo; final ActivityInfo activityInfo = taskInfo.topActivityInfo; if (activityInfo == null) { @@ -173,7 +176,8 @@ public class StartingSurfaceDrawer { : com.android.internal.R.style.Theme_DeviceDefault_DayNight; if (DEBUG_SPLASH_SCREEN) { 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. @@ -231,13 +235,19 @@ public class StartingSurfaceDrawer { params.setFitInsetsTypes(0); params.format = PixelFormat.TRANSLUCENT; int windowFlags = WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED - | WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR; final TypedArray a = context.obtainStyledAttributes(R.styleable.Window); if (a.getBoolean(R.styleable.Window_windowShowWallpaper, false)) { 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( R.styleable.Window_windowLayoutInDisplayCutoutMode, params.layoutInDisplayCutoutMode); @@ -311,12 +321,12 @@ public class StartingSurfaceDrawer { } Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); }; - mSplashscreenContentDrawer.createContentView(context, emptyView, activityInfo, taskId, + mSplashscreenContentDrawer.createContentView(context, suggestType, activityInfo, taskId, viewSupplier::setView); try { 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 // the window, as otherwise Choreographer#doFrame might be delayed on this thread. // And since Choreographer#doFrame won't happen immediately after adding the window, @@ -336,8 +346,10 @@ public class StartingSurfaceDrawer { int getStartingWindowBackgroundColorForTask(int taskId) { StartingWindowRecord startingWindowRecord = mStartingWindowRecords.get(taskId); - if (startingWindowRecord == null || startingWindowRecord.mContentView == null) return 0; - return ((ColorDrawable) startingWindowRecord.mContentView.getBackground()).getColor(); + if (startingWindowRecord == null || startingWindowRecord.mContentView == null) { + return 0; + } + return startingWindowRecord.mContentView.getInitBackgroundColor(); } private static class SplashScreenViewSupplier implements Supplier<SplashScreenView> { @@ -379,7 +391,7 @@ public class StartingSurfaceDrawer { return; } final StartingWindowRecord tView = new StartingWindowRecord(appToken, - null/* decorView */, surface); + null/* decorView */, surface, STARTING_WINDOW_TYPE_SNAPSHOT); mStartingWindowRecords.put(taskId, tView); } @@ -449,7 +461,7 @@ public class StartingSurfaceDrawer { } protected boolean addWindow(int taskId, IBinder appToken, View view, WindowManager wm, - WindowManager.LayoutParams params) { + WindowManager.LayoutParams params, @StartingWindowType int suggestType) { boolean shouldSaveView = true; try { Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "addRootView"); @@ -469,14 +481,15 @@ public class StartingSurfaceDrawer { } if (shouldSaveView) { removeWindowNoAnimate(taskId); - saveSplashScreenRecord(appToken, taskId, view); + saveSplashScreenRecord(appToken, taskId, view, suggestType); } 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, - null/* TaskSnapshotWindow */); + null/* TaskSnapshotWindow */, suggestType); mStartingWindowRecords.put(taskId, tView); } @@ -493,14 +506,18 @@ public class StartingSurfaceDrawer { Slog.v(TAG, "Removing splash screen window for task: " + taskId); } if (record.mContentView != null) { - if (playRevealAnimation) { - mSplashscreenContentDrawer.applyExitAnimation(record.mContentView, - leash, frame, - () -> removeWindowInner(record.mDecorView, true)); + if (record.mSuggestType == STARTING_WINDOW_TYPE_LEGACY_SPLASH_SCREEN) { + removeWindowInner(record.mDecorView, false); } else { - // the SplashScreenView has been copied to client, hide the view to skip - // default exit animation - removeWindowInner(record.mDecorView, true); + if (playRevealAnimation) { + mSplashscreenContentDrawer.applyExitAnimation(record.mContentView, + leash, frame, + () -> removeWindowInner(record.mDecorView, true)); + } else { + // the SplashScreenView has been copied to client, hide the view to skip + // default exit animation + removeWindowInner(record.mDecorView, true); + } } } else { // shouldn't happen @@ -537,6 +554,7 @@ public class StartingSurfaceDrawer { private final TaskSnapshotWindow mTaskSnapshotWindow; private SplashScreenView mContentView; private boolean mSetSplashScreen; + private @StartingWindowType int mSuggestType; StartingWindowRecord(IBinder appToken, View decorView, TaskSnapshotWindow taskSnapshotWindow) { @@ -545,6 +563,14 @@ public class StartingSurfaceDrawer { 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) { if (mSetSplashScreen) { return; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java index 9c1dde925762..eaa89d8e3ab5 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java @@ -17,6 +17,7 @@ package com.android.wm.shell.startingsurface; 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_SNAPSHOT; import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_SPLASH_SCREEN; @@ -31,6 +32,7 @@ import android.os.Trace; import android.util.Slog; import android.view.SurfaceControl; import android.window.StartingWindowInfo; +import android.window.StartingWindowInfo.StartingWindowType; import android.window.TaskOrganizer; import android.window.TaskSnapshot; @@ -106,10 +108,6 @@ public class StartingWindowController implements RemoteCallable<StartingWindowCo mTaskLaunchingCallback = listener; } - private boolean shouldSendToListener(int suggestionType) { - return suggestionType != STARTING_WINDOW_TYPE_EMPTY_SPLASH_SCREEN; - } - /** * Called when a task need a starting window. */ @@ -120,12 +118,9 @@ public class StartingWindowController implements RemoteCallable<StartingWindowCo final int suggestionType = mStartingWindowTypeAlgorithm.getSuggestedWindowType( windowInfo); final RunningTaskInfo runningTaskInfo = windowInfo.taskInfo; - if (suggestionType == STARTING_WINDOW_TYPE_SPLASH_SCREEN) { - mStartingSurfaceDrawer.addSplashScreenStartingWindow(windowInfo, appToken, - false /* emptyView */); - } else if (suggestionType == STARTING_WINDOW_TYPE_EMPTY_SPLASH_SCREEN) { + if (isSplashScreenType(suggestionType)) { mStartingSurfaceDrawer.addSplashScreenStartingWindow(windowInfo, appToken, - true /* emptyView */); + suggestionType); } else if (suggestionType == STARTING_WINDOW_TYPE_SNAPSHOT) { final TaskSnapshot snapshot = windowInfo.mTaskSnapshot; mStartingSurfaceDrawer.makeTaskSnapshotWindow(windowInfo, appToken, @@ -133,7 +128,7 @@ public class StartingWindowController implements RemoteCallable<StartingWindowCo } else /* suggestionType == STARTING_WINDOW_TYPE_NONE */ { // Don't add a staring window. } - if (mTaskLaunchingCallback != null && shouldSendToListener(suggestionType)) { + if (mTaskLaunchingCallback != null && isSplashScreenType(suggestionType)) { int taskId = runningTaskInfo.taskId; int color = mStartingSurfaceDrawer.getStartingWindowBackgroundColorForTask(taskId); mTaskLaunchingCallback.accept(taskId, suggestionType, color); @@ -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) { mSplashScreenExecutor.execute(() -> { mStartingSurfaceDrawer.copySplashScreenView(taskId); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/phone/PhoneStartingWindowTypeAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/phone/PhoneStartingWindowTypeAlgorithm.java index 5a134b806745..848eff4b56f3 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/phone/PhoneStartingWindowTypeAlgorithm.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/phone/PhoneStartingWindowTypeAlgorithm.java @@ -18,11 +18,13 @@ package com.android.wm.shell.startingsurface.phone; import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; 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_NONE; import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_SNAPSHOT; import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_SPLASH_SCREEN; import static android.window.StartingWindowInfo.TYPE_PARAMETER_ACTIVITY_CREATED; 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; import static android.window.StartingWindowInfo.TYPE_PARAMETER_PROCESS_RUNNING; import static android.window.StartingWindowInfo.TYPE_PARAMETER_TASK_SWITCH; @@ -54,30 +56,38 @@ public class PhoneStartingWindowTypeAlgorithm implements StartingWindowTypeAlgor final boolean activityCreated = (parameter & TYPE_PARAMETER_ACTIVITY_CREATED) != 0; final boolean useEmptySplashScreen = (parameter & TYPE_PARAMETER_USE_EMPTY_SPLASH_SCREEN) != 0; + final boolean legacySplashScreen = + ((parameter & TYPE_PARAMETER_LEGACY_SPLASH_SCREEN) != 0); final boolean topIsHome = windowInfo.taskInfo.topActivityType == ACTIVITY_TYPE_HOME; if (DEBUG_SPLASH_SCREEN || DEBUG_TASK_SNAPSHOT) { - Slog.d(TAG, "preferredStartingWindowType newTask " + newTask - + " taskSwitch " + taskSwitch - + " processRunning " + processRunning - + " allowTaskSnapshot " + allowTaskSnapshot - + " activityCreated " + activityCreated - + " useEmptySplashScreen " + useEmptySplashScreen - + " topIsHome " + topIsHome); + Slog.d(TAG, "preferredStartingWindowType newTask:" + newTask + + " taskSwitch:" + taskSwitch + + " processRunning:" + processRunning + + " allowTaskSnapshot:" + allowTaskSnapshot + + " activityCreated:" + activityCreated + + " useEmptySplashScreen:" + useEmptySplashScreen + + " legacySplashScreen:" + legacySplashScreen + + " topIsHome:" + topIsHome); } + + final int visibleSplashScreenType = legacySplashScreen + ? STARTING_WINDOW_TYPE_LEGACY_SPLASH_SCREEN + : STARTING_WINDOW_TYPE_SPLASH_SCREEN; + if (!topIsHome) { if (!processRunning) { return useEmptySplashScreen ? STARTING_WINDOW_TYPE_EMPTY_SPLASH_SCREEN - : STARTING_WINDOW_TYPE_SPLASH_SCREEN; + : visibleSplashScreenType; } if (newTask) { return useEmptySplashScreen ? STARTING_WINDOW_TYPE_EMPTY_SPLASH_SCREEN - : STARTING_WINDOW_TYPE_SPLASH_SCREEN; + : visibleSplashScreenType; } if (taskSwitch && !activityCreated) { - return STARTING_WINDOW_TYPE_SPLASH_SCREEN; + return visibleSplashScreenType; } } if (taskSwitch && allowTaskSnapshot) { diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java index 903e63ad6554..5061b2369bb2 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java @@ -15,6 +15,8 @@ */ package com.android.wm.shell.startingsurface; +import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_SPLASH_SCREEN; + import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy; @@ -91,7 +93,7 @@ public class StartingSurfaceDrawerTests { @Override protected boolean addWindow(int taskId, IBinder appToken, - View view, WindowManager wm, WindowManager.LayoutParams params) { + View view, WindowManager wm, WindowManager.LayoutParams params, int suggestType) { // listen for addView mAddWindowForTask = taskId; mViewThemeResId = view.getContext().getThemeResId(); @@ -145,9 +147,11 @@ public class StartingSurfaceDrawerTests { final int taskId = 1; final StartingWindowInfo windowInfo = createWindowInfo(taskId, android.R.style.Theme); - mStartingSurfaceDrawer.addSplashScreenStartingWindow(windowInfo, mBinder, false); + mStartingSurfaceDrawer.addSplashScreenStartingWindow(windowInfo, mBinder, + STARTING_WINDOW_TYPE_SPLASH_SCREEN); waitHandlerIdle(mTestHandler); - verify(mStartingSurfaceDrawer).addWindow(eq(taskId), eq(mBinder), any(), any(), any()); + verify(mStartingSurfaceDrawer).addWindow(eq(taskId), eq(mBinder), any(), any(), any(), + eq(STARTING_WINDOW_TYPE_SPLASH_SCREEN)); assertEquals(mStartingSurfaceDrawer.mAddWindowForTask, taskId); mStartingSurfaceDrawer.removeStartingWindow(windowInfo.taskInfo.taskId, null, null, false); @@ -161,9 +165,11 @@ public class StartingSurfaceDrawerTests { final int taskId = 1; final StartingWindowInfo windowInfo = createWindowInfo(taskId, 0); - mStartingSurfaceDrawer.addSplashScreenStartingWindow(windowInfo, mBinder, false); + mStartingSurfaceDrawer.addSplashScreenStartingWindow(windowInfo, mBinder, + STARTING_WINDOW_TYPE_SPLASH_SCREEN); waitHandlerIdle(mTestHandler); - verify(mStartingSurfaceDrawer).addWindow(eq(taskId), eq(mBinder), any(), any(), any()); + verify(mStartingSurfaceDrawer).addWindow(eq(taskId), eq(mBinder), any(), any(), any(), + eq(STARTING_WINDOW_TYPE_SPLASH_SCREEN)); assertNotEquals(mStartingSurfaceDrawer.mViewThemeResId, 0); } diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index d551f66c7387..64b5fc77dea7 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -257,6 +257,7 @@ import android.content.Intent; import android.content.LocusId; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; import android.content.res.CompatibilityInfo; import android.content.res.Configuration; import android.content.res.Resources; @@ -1929,12 +1930,23 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A final TaskSnapshot snapshot = mWmService.mTaskSnapshotController.getSnapshot(task.mTaskId, task.mUserId, false /* restoreFromDisk */, false /* isLowResolution */); - final int typeParameter = mWmService.mStartingSurfaceController - .makeStartingWindowTypeParameter(newTask, taskSwitch, processRunning, - allowTaskSnapshot, activityCreated, useEmpty); final int type = getStartingWindowType(newTask, taskSwitch, processRunning, allowTaskSnapshot, activityCreated, snapshot); + //TODO(191787740) Remove for T + final boolean useLegacy = type == STARTING_WINDOW_TYPE_SPLASH_SCREEN + && mWmService.mStartingSurfaceController.isExceptionApp(packageName, mTargetSdk, + () -> { + ActivityInfo activityInfo = intent.resolveActivityInfo( + mAtmService.mContext.getPackageManager(), + PackageManager.GET_META_DATA); + return activityInfo != null ? activityInfo.applicationInfo : null; + }); + + final int typeParameter = mWmService.mStartingSurfaceController + .makeStartingWindowTypeParameter(newTask, taskSwitch, processRunning, + allowTaskSnapshot, activityCreated, useEmpty, useLegacy); + if (type == STARTING_WINDOW_TYPE_SNAPSHOT) { if (isActivityTypeHome()) { // The snapshot of home is only used once because it won't be updated while screen diff --git a/services/core/java/com/android/server/wm/StartingSurfaceController.java b/services/core/java/com/android/server/wm/StartingSurfaceController.java index da257477b1d8..45b53a1a99b9 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_ALLOW_TASK_SNAPSHOT; +import static android.window.StartingWindowInfo.TYPE_PARAMETER_LEGACY_SPLASH_SCREEN; import static android.window.StartingWindowInfo.TYPE_PARAMETER_NEW_TASK; import static android.window.StartingWindowInfo.TYPE_PARAMETER_PROCESS_RUNNING; import static android.window.StartingWindowInfo.TYPE_PARAMETER_TASK_SWITCH; @@ -85,7 +86,7 @@ public class StartingSurfaceController { int makeStartingWindowTypeParameter(boolean newTask, boolean taskSwitch, boolean processRunning, boolean allowTaskSnapshot, boolean activityCreated, - boolean useEmpty) { + boolean useEmpty, boolean useLegacy) { int parameter = 0; if (newTask) { parameter |= TYPE_PARAMETER_NEW_TASK; @@ -105,6 +106,9 @@ public class StartingSurfaceController { if (useEmpty) { parameter |= TYPE_PARAMETER_USE_EMPTY_SPLASH_SCREEN; } + if (useLegacy) { + parameter |= TYPE_PARAMETER_LEGACY_SPLASH_SCREEN; + } return parameter; } diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java index b7713a9338de..a1f1610d95db 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java @@ -46,6 +46,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; import static android.view.WindowManager.TRANSIT_CLOSE; import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_OPEN; +import static android.window.StartingWindowInfo.TYPE_PARAMETER_LEGACY_SPLASH_SCREEN; import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; @@ -111,11 +112,13 @@ import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Point; import android.graphics.Rect; +import android.os.Build; import android.os.Bundle; import android.os.PersistableBundle; import android.os.Process; import android.os.RemoteException; import android.platform.test.annotations.Presubmit; +import android.provider.DeviceConfig; import android.util.MergedConfiguration; import android.util.MutableBoolean; import android.view.DisplayInfo; @@ -135,6 +138,7 @@ import androidx.test.filters.MediumTest; import com.android.internal.R; import com.android.server.wm.Task.ActivityState; +import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -2457,6 +2461,40 @@ public class ActivityRecordTests extends WindowTestsBase { assertNoStartingWindow(activity); } + private void testLegacySplashScreen(int targetSdk, int verifyType) { + final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build(); + activity.mTargetSdk = targetSdk; + activity.addStartingWindow(mPackageName, + android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true, + false, false); + waitUntilHandlersIdle(); + assertHasStartingWindow(activity); + assertEquals(activity.mStartingData.mTypeParams & TYPE_PARAMETER_LEGACY_SPLASH_SCREEN, + verifyType); + activity.removeStartingWindow(); + waitUntilHandlersIdle(); + assertNoStartingWindow(activity); + } + + @Test + public void testCreateRemoveLegacySplashScreenWindow() { + registerTestStartingWindowOrganizer(); + DeviceConfig.Properties properties = DeviceConfig.getProperties( + DeviceConfig.NAMESPACE_WINDOW_MANAGER); + try { + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_WINDOW_MANAGER, + "splash_screen_exception_list", DEFAULT_COMPONENT_PACKAGE_NAME, false); + testLegacySplashScreen(Build.VERSION_CODES.R, TYPE_PARAMETER_LEGACY_SPLASH_SCREEN); + testLegacySplashScreen(Build.VERSION_CODES.S, 0); + } finally { + try { + DeviceConfig.setProperties(properties); + } catch (DeviceConfig.BadConfigException e) { + Assert.fail(e.getMessage()); + } + } + } + @Test public void testTransferStartingWindow() { registerTestStartingWindowOrganizer(); |