Override Launcher's window bottom inset to 0 on large screen (tablet + unfolded phone) if all display cutouts are at bottom left/right corners

Bug: 321917681
Flag: NONE
Test: manual
Change-Id: I3c41d42e11413c73146c7ef59fc712971e96db19
This commit is contained in:
Fengjiang Li
2024-01-30 10:52:37 -08:00
parent 9ac91ffa63
commit 1707575da3
3 changed files with 221 additions and 2 deletions
@@ -17,6 +17,7 @@ package com.android.launcher3.util.window;
import static android.view.Display.DEFAULT_DISPLAY;
import static com.android.launcher3.Utilities.dpToPx;
import static com.android.launcher3.Utilities.dpiFromPx;
import static com.android.launcher3.testing.shared.ResourceUtils.INVALID_RESOURCE_HANDLE;
import static com.android.launcher3.testing.shared.ResourceUtils.NAVBAR_HEIGHT;
@@ -49,6 +50,9 @@ import android.view.WindowInsets;
import android.view.WindowManager;
import android.view.WindowMetrics;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.testing.shared.ResourceUtils;
@@ -130,11 +134,11 @@ public class WindowManagerProxy implements ResourceBasedOverride {
Resources systemRes = context.getResources();
Configuration config = systemRes.getConfiguration();
boolean isTablet = config.smallestScreenWidthDp > MIN_TABLET_WIDTH;
boolean isLargeScreen = config.smallestScreenWidthDp > MIN_TABLET_WIDTH;
boolean isGesture = isGestureNav(context);
boolean isPortrait = config.screenHeightDp > config.screenWidthDp;
int bottomNav = isTablet
int bottomNav = isLargeScreen
? 0
: (isPortrait
? getDimenByName(systemRes, NAVBAR_HEIGHT)
@@ -165,6 +169,9 @@ public class WindowManagerProxy implements ResourceBasedOverride {
insetsBuilder.setInsets(WindowInsets.Type.tappableElement(), newTappableInsets);
}
applyDisplayCutoutBottomInsetOverrideOnLargeScreen(
context, isLargeScreen, dpToPx(config.screenWidthDp), oldInsets, insetsBuilder);
WindowInsets result = insetsBuilder.build();
Insets systemWindowInsets = result.getInsetsIgnoringVisibility(
WindowInsets.Type.systemBars() | WindowInsets.Type.displayCutout());
@@ -173,6 +180,71 @@ public class WindowManagerProxy implements ResourceBasedOverride {
return result;
}
/**
* For large screen, when display cutout is at bottom left/right corner of screen, override
* display cutout's bottom inset to 0, because launcher allows drawing content over that area.
*/
private static void applyDisplayCutoutBottomInsetOverrideOnLargeScreen(
@NonNull Context context,
boolean isLargeScreen,
int screenWidthPx,
@NonNull WindowInsets windowInsets,
@NonNull WindowInsets.Builder insetsBuilder) {
if (!isLargeScreen || !Utilities.ATLEAST_S) {
return;
}
final DisplayCutout displayCutout = windowInsets.getDisplayCutout();
if (displayCutout == null) {
return;
}
if (!areBottomDisplayCutoutsSmallAndAtCorners(
displayCutout.getBoundingRectBottom(), screenWidthPx, context.getResources())) {
return;
}
Insets oldDisplayCutoutInset = windowInsets.getInsets(WindowInsets.Type.displayCutout());
Insets newDisplayCutoutInset = Insets.of(
oldDisplayCutoutInset.left,
oldDisplayCutoutInset.top,
oldDisplayCutoutInset.right,
0);
insetsBuilder.setInsetsIgnoringVisibility(
WindowInsets.Type.displayCutout(), newDisplayCutoutInset);
}
/**
* @see doc at {@link #areBottomDisplayCutoutsSmallAndAtCorners(Rect, int, int)}
*/
private static boolean areBottomDisplayCutoutsSmallAndAtCorners(
@NonNull Rect cutoutRectBottom, int screenWidthPx, @NonNull Resources res) {
return areBottomDisplayCutoutsSmallAndAtCorners(cutoutRectBottom, screenWidthPx,
res.getDimensionPixelSize(R.dimen.max_width_and_height_of_small_display_cutout));
}
/**
* Return true if bottom display cutouts are at bottom left/right corners, AND has width or
* height <= maxWidthAndHeightOfSmallCutoutPx. Note that display cutout rect and screenWidthPx
* passed to this method should be in the SAME screen rotation.
*
* @param cutoutRectBottom bottom display cutout rect, this is based on current screen rotation
* @param screenWidthPx screen width in px based on current screen rotation
* @param maxWidthAndHeightOfSmallCutoutPx maximum width and height pixels of cutout.
*/
@VisibleForTesting
static boolean areBottomDisplayCutoutsSmallAndAtCorners(
@NonNull Rect cutoutRectBottom, int screenWidthPx,
int maxWidthAndHeightOfSmallCutoutPx) {
// Empty cutoutRectBottom means there is no display cutout at the bottom. We should ignore
// it by returning false.
if (cutoutRectBottom.isEmpty()) {
return false;
}
return (cutoutRectBottom.right <= maxWidthAndHeightOfSmallCutoutPx)
|| cutoutRectBottom.left >= (screenWidthPx - maxWidthAndHeightOfSmallCutoutPx);
}
protected int getStatusBarHeight(Context context, boolean isPortrait, int statusBarInset) {
Resources systemRes = context.getResources();
int statusBarHeight = getDimenByName(systemRes,
@@ -249,6 +321,12 @@ public class WindowManagerProxy implements ResourceBasedOverride {
DisplayCutout rotatedCutout = rotateCutout(
displayInfo.cutout, displayInfo.size.x, displayInfo.size.y, rotation, i);
Rect insets = getSafeInsets(rotatedCutout);
if (areBottomDisplayCutoutsSmallAndAtCorners(
rotatedCutout.getBoundingRectBottom(),
bounds.width(),
context.getResources())) {
insets.bottom = 0;
}
insets.top = Math.max(insets.top, statusBarHeight);
insets.bottom = Math.max(insets.bottom, navBarHeight);