Merge "Implement the legacy splash screen behavior" into sc-dev am: 2be72d030b

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/14920934

Change-Id: If3cb25fa466589eed613c1b122e638533631a549
This commit is contained in:
Vadim Caen
2021-07-05 15:46:35 +00:00
committed by Automerger Merge Worker
10 changed files with 244 additions and 82 deletions

View File

@@ -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;
@@ -192,6 +194,14 @@ public final class SplashScreenView extends FrameLayout {
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.
*/
@@ -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;

View File

@@ -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.

View File

@@ -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();
}
splashScreenView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
@Override
public void onViewAttachedToWindow(View v) {
SplashScreenView.applySystemBarsContrastColor(v.getWindowInsetsController(),
splashScreenView.getInitBackgroundColor());
}
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) {
}
});
}
@Override
public void onViewDetachedFromWindow(View v) {
}
});
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
return splashScreenView;
}

View File

@@ -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;

View File

@@ -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) {
if (isSplashScreenType(suggestionType)) {
mStartingSurfaceDrawer.addSplashScreenStartingWindow(windowInfo, appToken,
false /* emptyView */);
} else if (suggestionType == STARTING_WINDOW_TYPE_EMPTY_SPLASH_SCREEN) {
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);

View File

@@ -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) {

View File

@@ -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);
}

View File

@@ -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;
@@ -2014,12 +2015,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

View File

@@ -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;
}

View File

@@ -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.ActivityRecord.State;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -2458,6 +2462,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();