Loading services/core/java/com/android/server/wm/AppCompatLetterboxPolicy.java +18 −109 Original line number Diff line number Diff line Loading @@ -26,9 +26,6 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.graphics.Point; import android.graphics.Rect; import android.view.InsetsSource; import android.view.InsetsState; import android.view.RoundedCorner; import android.view.SurfaceControl; import com.android.internal.annotations.VisibleForTesting; Loading @@ -44,12 +41,17 @@ class AppCompatLetterboxPolicy { private final ActivityRecord mActivityRecord; @NonNull private final LetterboxPolicyState mLetterboxPolicyState; @NonNull private final AppCompatRoundedCorners mAppCompatRoundedCorners; private boolean mLastShouldShowLetterboxUi; AppCompatLetterboxPolicy(@NonNull ActivityRecord activityRecord) { mActivityRecord = activityRecord; mLetterboxPolicyState = new LetterboxPolicyState(); // TODO (b/358334569) Improve cutout logic dependency on app compat. mAppCompatRoundedCorners = new AppCompatRoundedCorners(mActivityRecord, this::isLetterboxedNotForDisplayCutout); } /** Cleans up {@link Letterbox} if it exists.*/ Loading Loading @@ -105,7 +107,7 @@ class AppCompatLetterboxPolicy { if (shouldNotLayoutLetterbox(w)) { return; } updateRoundedCornersIfNeeded(w); mAppCompatRoundedCorners.updateRoundedCornersIfNeeded(w); updateWallpaperForLetterbox(w); if (shouldShowLetterboxUi(w)) { mLetterboxPolicyState.layoutLetterboxIfNeeded(w); Loading Loading @@ -138,94 +140,20 @@ class AppCompatLetterboxPolicy { @VisibleForTesting @Nullable Rect getCropBoundsIfNeeded(@NonNull final WindowState mainWindow) { if (!requiresRoundedCorners(mainWindow) || mActivityRecord.isInLetterboxAnimation()) { // We don't want corner radius on the window. // In the case the ActivityRecord requires a letterboxed animation we never want // rounded corners on the window because rounded corners are applied at the // animation-bounds surface level and rounded corners on the window would interfere // with that leading to unexpected rounded corner positioning during the animation. return null; } final Rect cropBounds = new Rect(mActivityRecord.getBounds()); // In case of translucent activities we check if the requested size is different from // the size provided using inherited bounds. In that case we decide to not apply rounded // corners because we assume the specific layout would. This is the case when the layout // of the translucent activity uses only a part of all the bounds because of the use of // LayoutParams.WRAP_CONTENT. final TransparentPolicy transparentPolicy = mActivityRecord.mAppCompatController .getTransparentPolicy(); if (transparentPolicy.isRunning() && (cropBounds.width() != mainWindow.mRequestedWidth || cropBounds.height() != mainWindow.mRequestedHeight)) { return null; } // It is important to call {@link #adjustBoundsIfNeeded} before {@link cropBounds.offsetTo} // because taskbar bounds used in {@link #adjustBoundsIfNeeded} // are in screen coordinates adjustBoundsForTaskbar(mainWindow, cropBounds); final float scale = mainWindow.mInvGlobalScale; if (scale != 1f && scale > 0f) { cropBounds.scale(scale); return mAppCompatRoundedCorners.getCropBoundsIfNeeded(mainWindow); } // ActivityRecord bounds are in screen coordinates while (0,0) for activity's surface // control is in the top left corner of an app window so offsetting bounds // accordingly. cropBounds.offsetTo(0, 0); return cropBounds; } // Returns rounded corners radius the letterboxed activity should have based on override in // R.integer.config_letterboxActivityCornersRadius or min device bottom corner radii. // Device corners can be different on the right and left sides, but we use the same radius // for all corners for consistency and pick a minimal bottom one for consistency with a // taskbar rounded corners. /** * Returns rounded corners radius the letterboxed activity should have based on override in * R.integer.config_letterboxActivityCornersRadius or min device bottom corner radii. * Device corners can be different on the right and left sides, but we use the same radius * for all corners for consistency and pick a minimal bottom one for consistency with a * taskbar rounded corners. * * @param mainWindow The {@link WindowState} to consider for the rounded corners calculation. */ int getRoundedCornersRadius(@NonNull final WindowState mainWindow) { if (!requiresRoundedCorners(mainWindow)) { return 0; } final AppCompatLetterboxOverrides letterboxOverrides = mActivityRecord .mAppCompatController.getAppCompatLetterboxOverrides(); final int radius; if (letterboxOverrides.getLetterboxActivityCornersRadius() >= 0) { radius = letterboxOverrides.getLetterboxActivityCornersRadius(); } else { final InsetsState insetsState = mainWindow.getInsetsState(); radius = Math.min( getInsetsStateCornerRadius(insetsState, RoundedCorner.POSITION_BOTTOM_LEFT), getInsetsStateCornerRadius(insetsState, RoundedCorner.POSITION_BOTTOM_RIGHT)); } final float scale = mainWindow.mInvGlobalScale; return (scale != 1f && scale > 0f) ? (int) (scale * radius) : radius; } void adjustBoundsForTaskbar(@NonNull final WindowState mainWindow, @NonNull final Rect bounds) { // Rounded corners should be displayed above the taskbar. When taskbar is hidden, // an insets frame is equal to a navigation bar which shouldn't affect position of // rounded corners since apps are expected to handle navigation bar inset. // This condition checks whether the taskbar is visible. // Do not crop the taskbar inset if the window is in immersive mode - the user can // swipe to show/hide the taskbar as an overlay. // Adjust the bounds only in case there is an expanded taskbar, // otherwise the rounded corners will be shown behind the navbar. final InsetsSource expandedTaskbarOrNull = AppCompatUtils.getExpandedTaskbarOrNull(mainWindow); if (expandedTaskbarOrNull != null) { // Rounded corners should be displayed above the expanded taskbar. bounds.bottom = Math.min(bounds.bottom, expandedTaskbarOrNull.getFrame().top); } } private int getInsetsStateCornerRadius(@NonNull InsetsState insetsState, @RoundedCorner.Position int position) { final RoundedCorner corner = insetsState.getRoundedCorners().getRoundedCorner(position); return corner == null ? 0 : corner.getRadius(); return mAppCompatRoundedCorners.getRoundedCornersRadius(mainWindow); } private void updateWallpaperForLetterbox(@NonNull WindowState mainWindow) { Loading @@ -248,25 +176,6 @@ class AppCompatLetterboxPolicy { } } void updateRoundedCornersIfNeeded(@NonNull final WindowState mainWindow) { final SurfaceControl windowSurface = mainWindow.getSurfaceControl(); if (windowSurface == null || !windowSurface.isValid()) { return; } // cropBounds must be non-null for the cornerRadius to be ever applied. mActivityRecord.getSyncTransaction() .setCrop(windowSurface, getCropBoundsIfNeeded(mainWindow)) .setCornerRadius(windowSurface, getRoundedCornersRadius(mainWindow)); } private boolean requiresRoundedCorners(@NonNull final WindowState mainWindow) { final AppCompatLetterboxOverrides letterboxOverrides = mActivityRecord .mAppCompatController.getAppCompatLetterboxOverrides(); return isLetterboxedNotForDisplayCutout(mainWindow) && letterboxOverrides.isLetterboxActivityCornersRounded(); } private boolean isLetterboxedNotForDisplayCutout(@NonNull WindowState mainWindow) { return shouldShowLetterboxUi(mainWindow) && !mainWindow.isLetterboxedForDisplayCutout(); Loading Loading @@ -405,7 +314,7 @@ class AppCompatLetterboxPolicy { outBounds.set(mLetterbox.getInnerFrame()); final WindowState w = mActivityRecord.findMainWindow(); if (w != null) { adjustBoundsForTaskbar(w, outBounds); AppCompatUtils.adjustBoundsForTaskbar(w, outBounds); } } else { outBounds.setEmpty(); Loading services/core/java/com/android/server/wm/AppCompatRoundedCorners.java 0 → 100644 +143 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.wm; import android.annotation.NonNull; import android.annotation.Nullable; import android.graphics.Rect; import android.view.InsetsState; import android.view.RoundedCorner; import android.view.SurfaceControl; import com.android.internal.annotations.VisibleForTesting; import java.util.function.Predicate; /** * Utility to unify rounded corners in app compat. */ class AppCompatRoundedCorners { @NonNull private final ActivityRecord mActivityRecord; @NonNull private final Predicate<WindowState> mIsLetterboxedNotForDisplayCutout; AppCompatRoundedCorners(@NonNull ActivityRecord activityRecord, @NonNull Predicate<WindowState> isLetterboxedNotForDisplayCutout) { mActivityRecord = activityRecord; mIsLetterboxedNotForDisplayCutout = isLetterboxedNotForDisplayCutout; } void updateRoundedCornersIfNeeded(@NonNull final WindowState mainWindow) { final SurfaceControl windowSurface = mainWindow.getSurfaceControl(); if (windowSurface == null || !windowSurface.isValid()) { return; } // cropBounds must be non-null for the cornerRadius to be ever applied. mActivityRecord.getSyncTransaction() .setCrop(windowSurface, getCropBoundsIfNeeded(mainWindow)) .setCornerRadius(windowSurface, getRoundedCornersRadius(mainWindow)); } @VisibleForTesting @Nullable Rect getCropBoundsIfNeeded(@NonNull final WindowState mainWindow) { if (!requiresRoundedCorners(mainWindow) || mActivityRecord.isInLetterboxAnimation()) { // We don't want corner radius on the window. // In the case the ActivityRecord requires a letterboxed animation we never want // rounded corners on the window because rounded corners are applied at the // animation-bounds surface level and rounded corners on the window would interfere // with that leading to unexpected rounded corner positioning during the animation. return null; } final Rect cropBounds = new Rect(mActivityRecord.getBounds()); // In case of translucent activities we check if the requested size is different from // the size provided using inherited bounds. In that case we decide to not apply rounded // corners because we assume the specific layout would. This is the case when the layout // of the translucent activity uses only a part of all the bounds because of the use of // LayoutParams.WRAP_CONTENT. final TransparentPolicy transparentPolicy = mActivityRecord.mAppCompatController .getTransparentPolicy(); if (transparentPolicy.isRunning() && (cropBounds.width() != mainWindow.mRequestedWidth || cropBounds.height() != mainWindow.mRequestedHeight)) { return null; } // It is important to call {@link #adjustBoundsIfNeeded} before {@link cropBounds.offsetTo} // because taskbar bounds used in {@link #adjustBoundsIfNeeded} // are in screen coordinates AppCompatUtils.adjustBoundsForTaskbar(mainWindow, cropBounds); final float scale = mainWindow.mInvGlobalScale; if (scale != 1f && scale > 0f) { cropBounds.scale(scale); } // ActivityRecord bounds are in screen coordinates while (0,0) for activity's surface // control is in the top left corner of an app window so offsetting bounds // accordingly. cropBounds.offsetTo(0, 0); return cropBounds; } /** * Returns rounded corners radius the letterboxed activity should have based on override in * R.integer.config_letterboxActivityCornersRadius or min device bottom corner radii. * Device corners can be different on the right and left sides, but we use the same radius * for all corners for consistency and pick a minimal bottom one for consistency with a * taskbar rounded corners. * * @param mainWindow The {@link WindowState} to consider for rounded corners calculation. */ int getRoundedCornersRadius(@NonNull final WindowState mainWindow) { if (!requiresRoundedCorners(mainWindow)) { return 0; } final AppCompatLetterboxOverrides letterboxOverrides = mActivityRecord .mAppCompatController.getAppCompatLetterboxOverrides(); final int radius; if (letterboxOverrides.getLetterboxActivityCornersRadius() >= 0) { radius = letterboxOverrides.getLetterboxActivityCornersRadius(); } else { final InsetsState insetsState = mainWindow.getInsetsState(); radius = Math.min( getInsetsStateCornerRadius(insetsState, RoundedCorner.POSITION_BOTTOM_LEFT), getInsetsStateCornerRadius(insetsState, RoundedCorner.POSITION_BOTTOM_RIGHT)); } final float scale = mainWindow.mInvGlobalScale; return (scale != 1f && scale > 0f) ? (int) (scale * radius) : radius; } private static int getInsetsStateCornerRadius(@NonNull InsetsState insetsState, @RoundedCorner.Position int position) { final RoundedCorner corner = insetsState.getRoundedCorners().getRoundedCorner(position); return corner == null ? 0 : corner.getRadius(); } private boolean requiresRoundedCorners(@NonNull final WindowState mainWindow) { final AppCompatLetterboxOverrides letterboxOverrides = mActivityRecord .mAppCompatController.getAppCompatLetterboxOverrides(); return mIsLetterboxedNotForDisplayCutout.test(mainWindow) && letterboxOverrides.isLetterboxActivityCornersRounded(); } } services/core/java/com/android/server/wm/AppCompatUtils.java +18 −1 Original line number Diff line number Diff line Loading @@ -37,7 +37,7 @@ import java.util.function.BooleanSupplier; /** * Utilities for App Compat policies and overrides. */ class AppCompatUtils { final class AppCompatUtils { /** * Lazy version of a {@link BooleanSupplier} which access an existing BooleanSupplier and Loading Loading @@ -232,6 +232,23 @@ class AppCompatUtils { return null; } static void adjustBoundsForTaskbar(@NonNull final WindowState mainWindow, @NonNull final Rect bounds) { // Rounded corners should be displayed above the taskbar. When taskbar is hidden, // an insets frame is equal to a navigation bar which shouldn't affect position of // rounded corners since apps are expected to handle navigation bar inset. // This condition checks whether the taskbar is visible. // Do not crop the taskbar inset if the window is in immersive mode - the user can // swipe to show/hide the taskbar as an overlay. // Adjust the bounds only in case there is an expanded taskbar, // otherwise the rounded corners will be shown behind the navbar. final InsetsSource expandedTaskbarOrNull = getExpandedTaskbarOrNull(mainWindow); if (expandedTaskbarOrNull != null) { // Rounded corners should be displayed above the expanded taskbar. bounds.bottom = Math.min(bounds.bottom, expandedTaskbarOrNull.getFrame().top); } } private static void clearAppCompatTaskInfo(@NonNull AppCompatTaskInfo info) { info.topActivityLetterboxVerticalPosition = TaskInfo.PROPERTY_VALUE_UNSET; info.topActivityLetterboxHorizontalPosition = TaskInfo.PROPERTY_VALUE_UNSET; Loading Loading
services/core/java/com/android/server/wm/AppCompatLetterboxPolicy.java +18 −109 Original line number Diff line number Diff line Loading @@ -26,9 +26,6 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.graphics.Point; import android.graphics.Rect; import android.view.InsetsSource; import android.view.InsetsState; import android.view.RoundedCorner; import android.view.SurfaceControl; import com.android.internal.annotations.VisibleForTesting; Loading @@ -44,12 +41,17 @@ class AppCompatLetterboxPolicy { private final ActivityRecord mActivityRecord; @NonNull private final LetterboxPolicyState mLetterboxPolicyState; @NonNull private final AppCompatRoundedCorners mAppCompatRoundedCorners; private boolean mLastShouldShowLetterboxUi; AppCompatLetterboxPolicy(@NonNull ActivityRecord activityRecord) { mActivityRecord = activityRecord; mLetterboxPolicyState = new LetterboxPolicyState(); // TODO (b/358334569) Improve cutout logic dependency on app compat. mAppCompatRoundedCorners = new AppCompatRoundedCorners(mActivityRecord, this::isLetterboxedNotForDisplayCutout); } /** Cleans up {@link Letterbox} if it exists.*/ Loading Loading @@ -105,7 +107,7 @@ class AppCompatLetterboxPolicy { if (shouldNotLayoutLetterbox(w)) { return; } updateRoundedCornersIfNeeded(w); mAppCompatRoundedCorners.updateRoundedCornersIfNeeded(w); updateWallpaperForLetterbox(w); if (shouldShowLetterboxUi(w)) { mLetterboxPolicyState.layoutLetterboxIfNeeded(w); Loading Loading @@ -138,94 +140,20 @@ class AppCompatLetterboxPolicy { @VisibleForTesting @Nullable Rect getCropBoundsIfNeeded(@NonNull final WindowState mainWindow) { if (!requiresRoundedCorners(mainWindow) || mActivityRecord.isInLetterboxAnimation()) { // We don't want corner radius on the window. // In the case the ActivityRecord requires a letterboxed animation we never want // rounded corners on the window because rounded corners are applied at the // animation-bounds surface level and rounded corners on the window would interfere // with that leading to unexpected rounded corner positioning during the animation. return null; } final Rect cropBounds = new Rect(mActivityRecord.getBounds()); // In case of translucent activities we check if the requested size is different from // the size provided using inherited bounds. In that case we decide to not apply rounded // corners because we assume the specific layout would. This is the case when the layout // of the translucent activity uses only a part of all the bounds because of the use of // LayoutParams.WRAP_CONTENT. final TransparentPolicy transparentPolicy = mActivityRecord.mAppCompatController .getTransparentPolicy(); if (transparentPolicy.isRunning() && (cropBounds.width() != mainWindow.mRequestedWidth || cropBounds.height() != mainWindow.mRequestedHeight)) { return null; } // It is important to call {@link #adjustBoundsIfNeeded} before {@link cropBounds.offsetTo} // because taskbar bounds used in {@link #adjustBoundsIfNeeded} // are in screen coordinates adjustBoundsForTaskbar(mainWindow, cropBounds); final float scale = mainWindow.mInvGlobalScale; if (scale != 1f && scale > 0f) { cropBounds.scale(scale); return mAppCompatRoundedCorners.getCropBoundsIfNeeded(mainWindow); } // ActivityRecord bounds are in screen coordinates while (0,0) for activity's surface // control is in the top left corner of an app window so offsetting bounds // accordingly. cropBounds.offsetTo(0, 0); return cropBounds; } // Returns rounded corners radius the letterboxed activity should have based on override in // R.integer.config_letterboxActivityCornersRadius or min device bottom corner radii. // Device corners can be different on the right and left sides, but we use the same radius // for all corners for consistency and pick a minimal bottom one for consistency with a // taskbar rounded corners. /** * Returns rounded corners radius the letterboxed activity should have based on override in * R.integer.config_letterboxActivityCornersRadius or min device bottom corner radii. * Device corners can be different on the right and left sides, but we use the same radius * for all corners for consistency and pick a minimal bottom one for consistency with a * taskbar rounded corners. * * @param mainWindow The {@link WindowState} to consider for the rounded corners calculation. */ int getRoundedCornersRadius(@NonNull final WindowState mainWindow) { if (!requiresRoundedCorners(mainWindow)) { return 0; } final AppCompatLetterboxOverrides letterboxOverrides = mActivityRecord .mAppCompatController.getAppCompatLetterboxOverrides(); final int radius; if (letterboxOverrides.getLetterboxActivityCornersRadius() >= 0) { radius = letterboxOverrides.getLetterboxActivityCornersRadius(); } else { final InsetsState insetsState = mainWindow.getInsetsState(); radius = Math.min( getInsetsStateCornerRadius(insetsState, RoundedCorner.POSITION_BOTTOM_LEFT), getInsetsStateCornerRadius(insetsState, RoundedCorner.POSITION_BOTTOM_RIGHT)); } final float scale = mainWindow.mInvGlobalScale; return (scale != 1f && scale > 0f) ? (int) (scale * radius) : radius; } void adjustBoundsForTaskbar(@NonNull final WindowState mainWindow, @NonNull final Rect bounds) { // Rounded corners should be displayed above the taskbar. When taskbar is hidden, // an insets frame is equal to a navigation bar which shouldn't affect position of // rounded corners since apps are expected to handle navigation bar inset. // This condition checks whether the taskbar is visible. // Do not crop the taskbar inset if the window is in immersive mode - the user can // swipe to show/hide the taskbar as an overlay. // Adjust the bounds only in case there is an expanded taskbar, // otherwise the rounded corners will be shown behind the navbar. final InsetsSource expandedTaskbarOrNull = AppCompatUtils.getExpandedTaskbarOrNull(mainWindow); if (expandedTaskbarOrNull != null) { // Rounded corners should be displayed above the expanded taskbar. bounds.bottom = Math.min(bounds.bottom, expandedTaskbarOrNull.getFrame().top); } } private int getInsetsStateCornerRadius(@NonNull InsetsState insetsState, @RoundedCorner.Position int position) { final RoundedCorner corner = insetsState.getRoundedCorners().getRoundedCorner(position); return corner == null ? 0 : corner.getRadius(); return mAppCompatRoundedCorners.getRoundedCornersRadius(mainWindow); } private void updateWallpaperForLetterbox(@NonNull WindowState mainWindow) { Loading @@ -248,25 +176,6 @@ class AppCompatLetterboxPolicy { } } void updateRoundedCornersIfNeeded(@NonNull final WindowState mainWindow) { final SurfaceControl windowSurface = mainWindow.getSurfaceControl(); if (windowSurface == null || !windowSurface.isValid()) { return; } // cropBounds must be non-null for the cornerRadius to be ever applied. mActivityRecord.getSyncTransaction() .setCrop(windowSurface, getCropBoundsIfNeeded(mainWindow)) .setCornerRadius(windowSurface, getRoundedCornersRadius(mainWindow)); } private boolean requiresRoundedCorners(@NonNull final WindowState mainWindow) { final AppCompatLetterboxOverrides letterboxOverrides = mActivityRecord .mAppCompatController.getAppCompatLetterboxOverrides(); return isLetterboxedNotForDisplayCutout(mainWindow) && letterboxOverrides.isLetterboxActivityCornersRounded(); } private boolean isLetterboxedNotForDisplayCutout(@NonNull WindowState mainWindow) { return shouldShowLetterboxUi(mainWindow) && !mainWindow.isLetterboxedForDisplayCutout(); Loading Loading @@ -405,7 +314,7 @@ class AppCompatLetterboxPolicy { outBounds.set(mLetterbox.getInnerFrame()); final WindowState w = mActivityRecord.findMainWindow(); if (w != null) { adjustBoundsForTaskbar(w, outBounds); AppCompatUtils.adjustBoundsForTaskbar(w, outBounds); } } else { outBounds.setEmpty(); Loading
services/core/java/com/android/server/wm/AppCompatRoundedCorners.java 0 → 100644 +143 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.wm; import android.annotation.NonNull; import android.annotation.Nullable; import android.graphics.Rect; import android.view.InsetsState; import android.view.RoundedCorner; import android.view.SurfaceControl; import com.android.internal.annotations.VisibleForTesting; import java.util.function.Predicate; /** * Utility to unify rounded corners in app compat. */ class AppCompatRoundedCorners { @NonNull private final ActivityRecord mActivityRecord; @NonNull private final Predicate<WindowState> mIsLetterboxedNotForDisplayCutout; AppCompatRoundedCorners(@NonNull ActivityRecord activityRecord, @NonNull Predicate<WindowState> isLetterboxedNotForDisplayCutout) { mActivityRecord = activityRecord; mIsLetterboxedNotForDisplayCutout = isLetterboxedNotForDisplayCutout; } void updateRoundedCornersIfNeeded(@NonNull final WindowState mainWindow) { final SurfaceControl windowSurface = mainWindow.getSurfaceControl(); if (windowSurface == null || !windowSurface.isValid()) { return; } // cropBounds must be non-null for the cornerRadius to be ever applied. mActivityRecord.getSyncTransaction() .setCrop(windowSurface, getCropBoundsIfNeeded(mainWindow)) .setCornerRadius(windowSurface, getRoundedCornersRadius(mainWindow)); } @VisibleForTesting @Nullable Rect getCropBoundsIfNeeded(@NonNull final WindowState mainWindow) { if (!requiresRoundedCorners(mainWindow) || mActivityRecord.isInLetterboxAnimation()) { // We don't want corner radius on the window. // In the case the ActivityRecord requires a letterboxed animation we never want // rounded corners on the window because rounded corners are applied at the // animation-bounds surface level and rounded corners on the window would interfere // with that leading to unexpected rounded corner positioning during the animation. return null; } final Rect cropBounds = new Rect(mActivityRecord.getBounds()); // In case of translucent activities we check if the requested size is different from // the size provided using inherited bounds. In that case we decide to not apply rounded // corners because we assume the specific layout would. This is the case when the layout // of the translucent activity uses only a part of all the bounds because of the use of // LayoutParams.WRAP_CONTENT. final TransparentPolicy transparentPolicy = mActivityRecord.mAppCompatController .getTransparentPolicy(); if (transparentPolicy.isRunning() && (cropBounds.width() != mainWindow.mRequestedWidth || cropBounds.height() != mainWindow.mRequestedHeight)) { return null; } // It is important to call {@link #adjustBoundsIfNeeded} before {@link cropBounds.offsetTo} // because taskbar bounds used in {@link #adjustBoundsIfNeeded} // are in screen coordinates AppCompatUtils.adjustBoundsForTaskbar(mainWindow, cropBounds); final float scale = mainWindow.mInvGlobalScale; if (scale != 1f && scale > 0f) { cropBounds.scale(scale); } // ActivityRecord bounds are in screen coordinates while (0,0) for activity's surface // control is in the top left corner of an app window so offsetting bounds // accordingly. cropBounds.offsetTo(0, 0); return cropBounds; } /** * Returns rounded corners radius the letterboxed activity should have based on override in * R.integer.config_letterboxActivityCornersRadius or min device bottom corner radii. * Device corners can be different on the right and left sides, but we use the same radius * for all corners for consistency and pick a minimal bottom one for consistency with a * taskbar rounded corners. * * @param mainWindow The {@link WindowState} to consider for rounded corners calculation. */ int getRoundedCornersRadius(@NonNull final WindowState mainWindow) { if (!requiresRoundedCorners(mainWindow)) { return 0; } final AppCompatLetterboxOverrides letterboxOverrides = mActivityRecord .mAppCompatController.getAppCompatLetterboxOverrides(); final int radius; if (letterboxOverrides.getLetterboxActivityCornersRadius() >= 0) { radius = letterboxOverrides.getLetterboxActivityCornersRadius(); } else { final InsetsState insetsState = mainWindow.getInsetsState(); radius = Math.min( getInsetsStateCornerRadius(insetsState, RoundedCorner.POSITION_BOTTOM_LEFT), getInsetsStateCornerRadius(insetsState, RoundedCorner.POSITION_BOTTOM_RIGHT)); } final float scale = mainWindow.mInvGlobalScale; return (scale != 1f && scale > 0f) ? (int) (scale * radius) : radius; } private static int getInsetsStateCornerRadius(@NonNull InsetsState insetsState, @RoundedCorner.Position int position) { final RoundedCorner corner = insetsState.getRoundedCorners().getRoundedCorner(position); return corner == null ? 0 : corner.getRadius(); } private boolean requiresRoundedCorners(@NonNull final WindowState mainWindow) { final AppCompatLetterboxOverrides letterboxOverrides = mActivityRecord .mAppCompatController.getAppCompatLetterboxOverrides(); return mIsLetterboxedNotForDisplayCutout.test(mainWindow) && letterboxOverrides.isLetterboxActivityCornersRounded(); } }
services/core/java/com/android/server/wm/AppCompatUtils.java +18 −1 Original line number Diff line number Diff line Loading @@ -37,7 +37,7 @@ import java.util.function.BooleanSupplier; /** * Utilities for App Compat policies and overrides. */ class AppCompatUtils { final class AppCompatUtils { /** * Lazy version of a {@link BooleanSupplier} which access an existing BooleanSupplier and Loading Loading @@ -232,6 +232,23 @@ class AppCompatUtils { return null; } static void adjustBoundsForTaskbar(@NonNull final WindowState mainWindow, @NonNull final Rect bounds) { // Rounded corners should be displayed above the taskbar. When taskbar is hidden, // an insets frame is equal to a navigation bar which shouldn't affect position of // rounded corners since apps are expected to handle navigation bar inset. // This condition checks whether the taskbar is visible. // Do not crop the taskbar inset if the window is in immersive mode - the user can // swipe to show/hide the taskbar as an overlay. // Adjust the bounds only in case there is an expanded taskbar, // otherwise the rounded corners will be shown behind the navbar. final InsetsSource expandedTaskbarOrNull = getExpandedTaskbarOrNull(mainWindow); if (expandedTaskbarOrNull != null) { // Rounded corners should be displayed above the expanded taskbar. bounds.bottom = Math.min(bounds.bottom, expandedTaskbarOrNull.getFrame().top); } } private static void clearAppCompatTaskInfo(@NonNull AppCompatTaskInfo info) { info.topActivityLetterboxVerticalPosition = TaskInfo.PROPERTY_VALUE_UNSET; info.topActivityLetterboxHorizontalPosition = TaskInfo.PROPERTY_VALUE_UNSET; Loading