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:
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user