diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 295943da12622..854c9f2a5b3ab 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -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; } /** diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index b1438eae65064..f626d4bda393a 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -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); } } } diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java index 5fb4e705c8313..1499acec9af75 100644 --- a/core/java/android/view/Window.java +++ b/core/java/android/view/Window.java @@ -1354,6 +1354,11 @@ public abstract class Window { public void setDecorFitsSystemWindows(boolean decorFitsSystemWindows) { } + /** @hide */ + public boolean decorFitsSystemWindows() { + return false; + } + /** * Specify custom window attributes. PLEASE NOTE: the * layout params you give here should generally be from values previously diff --git a/core/java/android/window/SplashScreenView.java b/core/java/android/window/SplashScreenView.java index 8debe5d569a3a..d67fb3233a3b9 100644 --- a/core/java/android/window/SplashScreenView.java +++ b/core/java/android/window/SplashScreenView.java @@ -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); } /** diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java index 0ea299ddef010..1a23cc11fca8d 100644 --- a/core/java/com/android/internal/policy/PhoneWindow.java +++ b/core/java/com/android/internal/policy/PhoneWindow.java @@ -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) { 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 81e87f13e134a..a646231d175bf 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 @@ -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; } 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 26e8753ad3cf6..187e104c9bfb6 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 @@ -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.