Merge "Draw splashscreen edge to edge" into sc-dev am: eacda76449

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

Change-Id: I2d837e43fe9c75b95abbe9faad580c3470c23e9e
This commit is contained in:
Vadim Caen
2021-05-18 11:33:42 +00:00
committed by Automerger Merge Worker
7 changed files with 117 additions and 104 deletions

View File

@@ -970,8 +970,7 @@ public class Activity extends ContextThemeWrapper
private UiTranslationController mUiTranslationController;
private SplashScreen mSplashScreen;
/** @hide */
SplashScreenView mSplashScreenView;
private SplashScreenView mSplashScreenView;
private final WindowControllerCallback mWindowControllerCallback =
new WindowControllerCallback() {
@@ -1631,16 +1630,14 @@ public class Activity extends ContextThemeWrapper
}
}
/**
* Clear the splash screen view if exist.
* @hide
*/
public void detachSplashScreenView() {
synchronized (this) {
if (mSplashScreenView != null) {
mSplashScreenView = null;
}
}
/** @hide */
public void setSplashScreenView(SplashScreenView v) {
mSplashScreenView = v;
}
/** @hide */
SplashScreenView getSplashScreenView() {
return mSplashScreenView;
}
/**

View File

@@ -4051,10 +4051,7 @@ public final class ActivityThread extends ClientTransactionHandler
final SplashScreenView.Builder builder = new SplashScreenView.Builder(r.activity);
final SplashScreenView view = builder.createFromParcel(parcelable).build();
decorView.addView(view);
view.cacheRootWindow(r.window);
view.makeSystemUIColorsTransparent();
r.activity.mSplashScreenView = view;
view.attachHostActivity(r.activity);
view.attachHostActivityAndSetSystemUIColors(r.activity, r.window);
view.requestLayout();
// Ensure splash screen view is shown before remove the splash screen window.
final ViewRootImpl impl = decorView.getViewRootImpl();
@@ -4096,12 +4093,13 @@ public final class ActivityThread extends ClientTransactionHandler
@Override
public void handOverSplashScreenView(@NonNull ActivityClientRecord r) {
if (r.activity.mSplashScreenView != null) {
synchronized (this) {
if (mSplashScreenGlobal != null) {
mSplashScreenGlobal.dispatchOnExitAnimation(r.token,
r.activity.mSplashScreenView);
}
final SplashScreenView v = r.activity.getSplashScreenView();
if (v == null) {
return;
}
synchronized (this) {
if (mSplashScreenGlobal != null) {
mSplashScreenGlobal.dispatchOnExitAnimation(r.token, v);
}
}
}

View File

@@ -1354,6 +1354,11 @@ public abstract class Window {
public void setDecorFitsSystemWindows(boolean decorFitsSystemWindows) {
}
/** @hide */
public boolean decorFitsSystemWindows() {
return false;
}
/**
* Specify custom window attributes. <strong>PLEASE NOTE:</strong> the
* layout params you give here should generally be from values previously

View File

@@ -17,6 +17,8 @@ package android.window;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
import android.annotation.ColorInt;
import android.annotation.NonNull;
@@ -40,11 +42,13 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowInsetsController;
import android.view.WindowManager;
import android.widget.FrameLayout;
import com.android.internal.R;
import com.android.internal.policy.DecorView;
import com.android.internal.util.ContrastColorUtil;
import java.time.Duration;
import java.time.Instant;
@@ -69,6 +73,12 @@ public final class SplashScreenView extends FrameLayout {
private static final String TAG = SplashScreenView.class.getSimpleName();
private static final boolean DEBUG = false;
private static final int LIGHT_BARS_MASK =
WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS
| WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS;
private static final int WINDOW_FLAG_MASK = FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS
| FLAG_TRANSLUCENT_NAVIGATION | FLAG_TRANSLUCENT_STATUS;
private boolean mNotCopyable;
private boolean mRevealAnimationSupported = true;
private int mInitBackgroundColor;
@@ -84,10 +94,14 @@ public final class SplashScreenView extends FrameLayout {
private Activity mHostActivity;
// cache original window and status
private Window mWindow;
private boolean mDrawBarBackground;
private int mAppWindowFlags;
private int mStatusBarColor;
private int mNavigationBarColor;
private int mSystemBarsAppearance;
private boolean mHasRemoved;
private boolean mNavigationContrastEnforced;
private boolean mStatusContrastEnforced;
private boolean mDecorFitsSystemWindows;
/**
* Internal builder to create a SplashScreenView object.
@@ -347,54 +361,63 @@ public final class SplashScreenView extends FrameLayout {
mWindow = null;
}
if (mHostActivity != null) {
mHostActivity.detachSplashScreenView();
mHostActivity.setSplashScreenView(null);
mHostActivity = null;
}
mHasRemoved = true;
}
/**
* Called when this view is attached to an activity.
* Called when this view is attached to an activity. This also makes SystemUI colors
* transparent so the content of splash screen view can draw fully.
* @hide
*/
public void attachHostActivity(Activity activity) {
public void attachHostActivityAndSetSystemUIColors(Activity activity, Window window) {
activity.setSplashScreenView(this);
mHostActivity = activity;
}
/**
* Cache the root window.
* @hide
*/
public void cacheRootWindow(Window window) {
mWindow = window;
final WindowManager.LayoutParams attr = window.getAttributes();
mAppWindowFlags = attr.flags;
mStatusBarColor = window.getStatusBarColor();
mNavigationBarColor = window.getNavigationBarColor();
mSystemBarsAppearance = window.getInsetsController().getSystemBarsAppearance();
mNavigationContrastEnforced = window.isNavigationBarContrastEnforced();
mStatusContrastEnforced = window.isStatusBarContrastEnforced();
mDecorFitsSystemWindows = window.decorFitsSystemWindows();
applySystemBarsContrastColor(window.getInsetsController(), mInitBackgroundColor);
// Let app draw the background of bars.
window.addFlags(FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
// Use specified bar colors instead of window background.
window.clearFlags(FLAG_TRANSLUCENT_STATUS | FLAG_TRANSLUCENT_NAVIGATION);
window.setStatusBarColor(Color.TRANSPARENT);
window.setNavigationBarColor(Color.TRANSPARENT);
window.setDecorFitsSystemWindows(false);
window.setStatusBarContrastEnforced(false);
window.setNavigationBarContrastEnforced(false);
}
/** Called when this view is removed from the host activity. */
private void restoreSystemUIColors() {
mWindow.setFlags(mAppWindowFlags, WINDOW_FLAG_MASK);
mWindow.setStatusBarColor(mStatusBarColor);
mWindow.setNavigationBarColor(mNavigationBarColor);
mWindow.getInsetsController().setSystemBarsAppearance(mSystemBarsAppearance,
LIGHT_BARS_MASK);
mWindow.setDecorFitsSystemWindows(mDecorFitsSystemWindows);
mWindow.setStatusBarContrastEnforced(mStatusContrastEnforced);
mWindow.setNavigationBarContrastEnforced(mNavigationContrastEnforced);
}
/**
* Called after SplashScreenView has added on the root window.
* Makes the icon color of system bars contrast.
* @hide
*/
public void makeSystemUIColorsTransparent() {
if (mWindow != null) {
final WindowManager.LayoutParams attr = mWindow.getAttributes();
mDrawBarBackground = (attr.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0;
mWindow.addFlags(FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
mStatusBarColor = mWindow.getStatusBarColor();
mNavigationBarColor = mWindow.getNavigationBarDividerColor();
mWindow.setStatusBarColor(Color.TRANSPARENT);
mWindow.setNavigationBarColor(Color.TRANSPARENT);
}
setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
}
private void restoreSystemUIColors() {
if (mWindow != null) {
if (!mDrawBarBackground) {
mWindow.clearFlags(FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
}
mWindow.setStatusBarColor(mStatusBarColor);
mWindow.setNavigationBarColor(mNavigationBarColor);
}
public static void applySystemBarsContrastColor(WindowInsetsController windowInsetsController,
int backgroundColor) {
final int lightBarAppearance = ContrastColorUtil.isColorLight(backgroundColor)
? LIGHT_BARS_MASK : 0;
windowInsetsController.setSystemBarsAppearance(lightBarAppearance, LIGHT_BARS_MASK);
}
/**

View File

@@ -3931,6 +3931,11 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
applyDecorFitsSystemWindows();
}
@Override
public boolean decorFitsSystemWindows() {
return mDecorFitsSystemWindows;
}
private void applyDecorFitsSystemWindows() {
ViewRootImpl impl = getViewRootImplOrNull();
if (impl != null) {

View File

@@ -39,6 +39,7 @@ import android.os.HandlerThread;
import android.os.Trace;
import android.util.Slog;
import android.view.SurfaceControl;
import android.view.View;
import android.window.SplashScreenView;
import com.android.internal.R;
@@ -398,7 +399,17 @@ public class SplashscreenContentDrawer {
splashScreenView.setNotCopyable();
splashScreenView.setRevealAnimationSupported(false);
}
splashScreenView.makeSystemUIColorsTransparent();
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;
}

View File

@@ -25,12 +25,10 @@ import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityTaskManager;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.hardware.display.DisplayManager;
import android.os.IBinder;
@@ -43,13 +41,13 @@ import android.view.Display;
import android.view.SurfaceControl;
import android.view.View;
import android.view.WindowManager;
import android.widget.FrameLayout;
import android.window.SplashScreenView;
import android.window.SplashScreenView.SplashScreenViewParcelable;
import android.window.StartingWindowInfo;
import android.window.TaskSnapshot;
import com.android.internal.R;
import com.android.internal.policy.PhoneWindow;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.TransactionPool;
@@ -152,14 +150,6 @@ public class StartingSurfaceDrawer {
return;
}
CharSequence nonLocalizedLabel = activityInfo.nonLocalizedLabel;
int labelRes = activityInfo.labelRes;
if (activityInfo.nonLocalizedLabel == null && activityInfo.labelRes == 0) {
ApplicationInfo app = activityInfo.applicationInfo;
nonLocalizedLabel = app.nonLocalizedLabel;
labelRes = app.labelRes;
}
final int taskId = taskInfo.taskId;
Context context = mContext;
// replace with the default theme if the application didn't set
@@ -169,8 +159,7 @@ public class StartingSurfaceDrawer {
: com.android.internal.R.style.Theme_DeviceDefault_DayNight;
if (DEBUG_SPLASH_SCREEN) {
Slog.d(TAG, "addSplashScreen " + activityInfo.packageName
+ ": nonLocalizedLabel=" + nonLocalizedLabel + " theme="
+ Integer.toHexString(theme) + " task= " + taskInfo.taskId);
+ " theme=" + Integer.toHexString(theme) + " task= " + taskInfo.taskId);
}
// Obtain proper context to launch on the right display.
@@ -180,7 +169,7 @@ public class StartingSurfaceDrawer {
return;
}
context = displayContext;
if (theme != context.getThemeResId() || labelRes != 0) {
if (theme != context.getThemeResId()) {
try {
context = context.createPackageContextAsUser(activityInfo.packageName,
CONTEXT_RESTRICTED, UserHandle.of(taskInfo.userId));
@@ -222,23 +211,22 @@ public class StartingSurfaceDrawer {
typedArray.recycle();
}
final PhoneWindow win = new PhoneWindow(context);
win.setIsStartingWindow(true);
final Resources res = context.getResources();
final CharSequence label = res.getText(labelRes, null);
// Only change the accessibility title if the label is localized
if (label != null) {
win.setTitle(label, true);
} else {
win.setTitle(nonLocalizedLabel, false);
}
int windowFlags = WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.TYPE_APPLICATION_STARTING);
params.setFitInsetsSides(0);
params.setFitInsetsTypes(0);
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;
}
params.layoutInDisplayCutoutMode = a.getInt(
R.styleable.Window_windowLayoutInDisplayCutoutMode,
params.layoutInDisplayCutoutMode);
params.windowAnimations = a.getResourceId(R.styleable.Window_windowAnimationStyle, 0);
a.recycle();
// Assumes it's safe to show starting windows of launched apps while
@@ -256,28 +244,15 @@ public class StartingSurfaceDrawer {
windowFlags |= WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
win.setFlags(windowFlags, windowFlags);
final int iconRes = activityInfo.getIconResource();
final int logoRes = activityInfo.getLogoResource();
win.setDefaultIcon(iconRes);
win.setDefaultLogo(logoRes);
final WindowManager.LayoutParams params = win.getAttributes();
params.type = WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
params.width = WindowManager.LayoutParams.MATCH_PARENT;
params.height = WindowManager.LayoutParams.MATCH_PARENT;
params.flags = windowFlags;
params.token = appToken;
params.packageName = activityInfo.packageName;
params.windowAnimations = win.getWindowStyle().getResourceId(
com.android.internal.R.styleable.Window_windowAnimationStyle, 0);
params.privateFlags |= WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
// Setting as trusted overlay to let touches pass through. This is safe because this
// window is controlled by the system.
params.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
params.format = PixelFormat.RGBA_8888;
if (!res.getCompatibilityInfo().supportsScreen()) {
if (!context.getResources().getCompatibilityInfo().supportsScreen()) {
params.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
}
@@ -297,6 +272,7 @@ public class StartingSurfaceDrawer {
// Record whether create splash screen view success, notify to current thread after
// create splash screen view finished.
final SplashScreenViewSupplier viewSupplier = new SplashScreenViewSupplier();
final FrameLayout rootLayout = new FrameLayout(context);
final Runnable setViewSynchronized = () -> {
// waiting for setContentView before relayoutWindow
SplashScreenView contentView = viewSupplier.get();
@@ -306,8 +282,7 @@ public class StartingSurfaceDrawer {
// if view == null then creation of content view was failed.
if (contentView != null) {
try {
win.setContentView(contentView);
contentView.cacheRootWindow(win);
rootLayout.addView(contentView);
} catch (RuntimeException e) {
Slog.w(TAG, "failed set content view to starting window "
+ "at taskId: " + taskId, e);
@@ -321,9 +296,8 @@ public class StartingSurfaceDrawer {
viewSupplier::setView);
try {
final View view = win.getDecorView();
final WindowManager wm = context.getSystemService(WindowManager.class);
postAddWindow(taskId, appToken, view, wm, params);
postAddWindow(taskId, appToken, rootLayout, wm, params);
// We use the splash screen worker thread to create SplashScreenView while adding the
// window, as otherwise Choreographer#doFrame might be delayed on this thread.