Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5d85528c authored by Nick Chameyev's avatar Nick Chameyev
Browse files

Update cache key calculation for statusbar insets

We use Display#uniqueId as a cache key for status
bar insets when using multiple displays (e.g. foldable
device). But uniqueId and display size could be
inconsistent (see b/198965093#comment13): we could
receive uniqueId for a different display than the
current display size in the configuration.
So if it is calculated once with wrong display size
it is saved in the cache and status bar is rendered
with wrong insets every time.

I updated the cache key calculation with the actual
inputs of the calculation algorithm (display size
and cutouts) which are consistent when
onConfigurationChange received.

Bug: 212924195
Test: folding and unlocking a foldable phone >1000 times,
 rotating when folded/unfolded
 => checking that the statusbar has correct size
Change-Id: Ibd8575529b031747a802b56db3eb12069b9ba6b0
Merged-In: Ibd8575529b031747a802b56db3eb12069b9ba6b0
parent f775a46d
Loading
Loading
Loading
Loading
+13 −4
Original line number Diff line number Diff line
@@ -53,6 +53,8 @@ public class PhoneStatusBarView extends FrameLayout {
    private View mCutoutSpace;
    @Nullable
    private DisplayCutout mDisplayCutout;
    @Nullable
    private Rect mDisplaySize;
    private int mStatusBarHeight;
    @Nullable
    private TouchEventHandler mTouchEventHandler;
@@ -87,7 +89,7 @@ public class PhoneStatusBarView extends FrameLayout {
        // Always have Battery meters in the status bar observe the dark/light modes.
        Dependency.get(DarkIconDispatcher.class).addDarkReceiver(mBattery);
        Dependency.get(DarkIconDispatcher.class).addDarkReceiver(mClock);
        if (updateOrientationAndCutout()) {
        if (updateDisplayParameters()) {
            updateLayoutForCutout();
        }
    }
@@ -106,7 +108,7 @@ public class PhoneStatusBarView extends FrameLayout {
        updateResources();

        // May trigger cutout space layout-ing
        if (updateOrientationAndCutout()) {
        if (updateDisplayParameters()) {
            updateLayoutForCutout();
            requestLayout();
        }
@@ -114,7 +116,7 @@ public class PhoneStatusBarView extends FrameLayout {

    @Override
    public WindowInsets onApplyWindowInsets(WindowInsets insets) {
        if (updateOrientationAndCutout()) {
        if (updateDisplayParameters()) {
            updateLayoutForCutout();
            requestLayout();
        }
@@ -124,7 +126,7 @@ public class PhoneStatusBarView extends FrameLayout {
    /**
     * @return boolean indicating if we need to update the cutout location / margins
     */
    private boolean updateOrientationAndCutout() {
    private boolean updateDisplayParameters() {
        boolean changed = false;
        int newRotation = RotationUtils.getExactRotation(mContext);
        if (newRotation != mRotationOrientation) {
@@ -137,6 +139,13 @@ public class PhoneStatusBarView extends FrameLayout {
            mDisplayCutout = getRootWindowInsets().getDisplayCutout();
        }

        final Rect newSize = mContext.getResources().getConfiguration().windowConfiguration
                .getMaxBounds();
        if (!Objects.equals(newSize, mDisplaySize)) {
            changed = true;
            mDisplaySize = newSize;
        }

        return changed;
    }

+38 −26
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@ import com.android.systemui.util.leak.RotationUtils.ROTATION_UPSIDE_DOWN
import com.android.systemui.util.leak.RotationUtils.Rotation
import com.android.systemui.util.leak.RotationUtils.getExactRotation
import com.android.systemui.util.leak.RotationUtils.getResourcesForRotation
import com.android.systemui.util.traceSection

import java.io.PrintWriter
import java.lang.Math.max
@@ -133,8 +134,10 @@ class StatusBarContentInsetsProvider @Inject constructor(
     *      (i.e., ROTATION_NONE will always return the same bounds regardless of the context
     *      from which this method is called)
     */
    fun getBoundingRectForPrivacyChipForRotation(@Rotation rotation: Int): Rect {
        var insets = insetsCache[getCacheKey(rotation = rotation)]
    fun getBoundingRectForPrivacyChipForRotation(@Rotation rotation: Int,
                                                 displayCutout: DisplayCutout?): Rect {
        val key = getCacheKey(rotation, displayCutout)
        var insets = insetsCache[key]
        if (insets == null) {
            insets = getStatusBarContentAreaForRotation(rotation)
        }
@@ -156,19 +159,22 @@ class StatusBarContentInsetsProvider @Inject constructor(
     *
     * @param rotation the target rotation for which to calculate insets
     */
    fun getStatusBarContentInsetsForRotation(@Rotation rotation: Int): Pair<Int, Int> {
        val key = getCacheKey(rotation)
    fun getStatusBarContentInsetsForRotation(@Rotation rotation: Int): Pair<Int, Int> =
        traceSection(tag = "StatusBarContentInsetsProvider.getStatusBarContentInsetsForRotation") {
            val displayCutout = context.display.cutout
            val key = getCacheKey(rotation, displayCutout)

            val screenBounds = context.resources.configuration.windowConfiguration.maxBounds
            val point = Point(screenBounds.width(), screenBounds.height())

        val point = Point()
        context.display.getRealSize(point)
            // Target rotation can be a different orientation than the current device rotation
            point.orientToRotZero(getExactRotation(context))
            val width = point.logicalWidth(rotation)

            val area = insetsCache[key] ?: getAndSetCalculatedAreaForRotation(
                rotation, getResourcesForRotation(rotation, context), key)
                rotation, displayCutout, getResourcesForRotation(rotation, context), key)

        return Pair(area.left, width - area.right)
            Pair(area.left, width - area.right)
        }

    /**
@@ -192,9 +198,10 @@ class StatusBarContentInsetsProvider @Inject constructor(
    fun getStatusBarContentAreaForRotation(
        @Rotation rotation: Int
    ): Rect {
        val key = getCacheKey(rotation)
        val displayCutout = context.display.cutout
        val key = getCacheKey(rotation, displayCutout)
        return insetsCache[key] ?: getAndSetCalculatedAreaForRotation(
                rotation, getResourcesForRotation(rotation, context), key)
                rotation, displayCutout, getResourcesForRotation(rotation, context), key)
    }

    /**
@@ -207,20 +214,21 @@ class StatusBarContentInsetsProvider @Inject constructor(

    private fun getAndSetCalculatedAreaForRotation(
        @Rotation targetRotation: Int,
        displayCutout: DisplayCutout?,
        rotatedResources: Resources,
        key: CacheKey
    ): Rect {
        return getCalculatedAreaForRotation(targetRotation, rotatedResources)
        return getCalculatedAreaForRotation(displayCutout, targetRotation, rotatedResources)
                .also {
                    insetsCache.put(key, it)
                }
    }

    private fun getCalculatedAreaForRotation(
        displayCutout: DisplayCutout?,
        @Rotation targetRotation: Int,
        rotatedResources: Resources
    ): Rect {
        val dc = context.display.cutout
        val currentRotation = getExactRotation(context)

        val roundedCornerPadding = rotatedResources
@@ -245,7 +253,7 @@ class StatusBarContentInsetsProvider @Inject constructor(
        return calculateInsetsForRotationWithRotatedResources(
                currentRotation,
                targetRotation,
                dc,
                displayCutout,
                context.resources.configuration.windowConfiguration.maxBounds,
                SystemBarUtils.getStatusBarHeightForRotation(context, targetRotation),
                minLeft,
@@ -266,15 +274,19 @@ class StatusBarContentInsetsProvider @Inject constructor(
        pw.println(insetsCache)
    }

    private fun getCacheKey(@Rotation rotation: Int): CacheKey =
    private fun getCacheKey(
            @Rotation rotation: Int,
            displayCutout: DisplayCutout?): CacheKey =
        CacheKey(
            uniqueDisplayId = context.display.uniqueId,
            rotation = rotation
            rotation = rotation,
            displaySize = Rect(context.resources.configuration.windowConfiguration.maxBounds),
            displayCutout = displayCutout
        )

    private data class CacheKey(
        val uniqueDisplayId: String,
        @Rotation val rotation: Int
        @Rotation val rotation: Int,
        val displaySize: Rect,
        val displayCutout: DisplayCutout?
    )
}

@@ -369,7 +381,7 @@ fun calculateInsetsForRotationWithRotatedResources(
/**
 * Calculate the insets needed from the left and right edges for the given rotation.
 *
 * @param dc Device display cutout
 * @param displayCutout Device display cutout
 * @param sbHeight appropriate status bar height for this rotation
 * @param width display width calculated for ROTATION_NONE
 * @param height display height calculated for ROTATION_NONE
@@ -386,7 +398,7 @@ fun calculateInsetsForRotationWithRotatedResources(
 * rotation
 */
private fun getStatusBarLeftRight(
    dc: DisplayCutout?,
    displayCutout: DisplayCutout?,
    sbHeight: Int,
    width: Int,
    height: Int,
@@ -402,7 +414,7 @@ private fun getStatusBarLeftRight(

    val logicalDisplayWidth = if (targetRotation.isHorizontal()) height else width

    val cutoutRects = dc?.boundingRects
    val cutoutRects = displayCutout?.boundingRects
    if (cutoutRects == null || cutoutRects.isEmpty()) {
        return Rect(minLeft,
                0,
+9 −4
Original line number Diff line number Diff line
@@ -31,7 +31,9 @@ import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.os.Binder;
import android.os.RemoteException;
import android.os.Trace;
import android.util.Log;
import android.view.DisplayCutout;
import android.view.Gravity;
import android.view.IWindowManager;
import android.view.Surface;
@@ -130,7 +132,9 @@ public class StatusBarWindowController {
        // Now that the status bar window encompasses the sliding panel and its
        // translucent backdrop, the entire thing is made TRANSLUCENT and is
        // hardware-accelerated.
        Trace.beginSection("StatusBarWindowController.getBarLayoutParams");
        mLp = getBarLayoutParams(mContext.getDisplay().getRotation());
        Trace.endSection();

        mWindowManager.addView(mStatusBarWindowView, mLp);
        mLpChanged.copyFrom(mLp);
@@ -223,14 +227,15 @@ public class StatusBarWindowController {

    private void calculateStatusBarLocationsForAllRotations() {
        Rect[] bounds = new Rect[4];
        final DisplayCutout displayCutout = mContext.getDisplay().getCutout();
        bounds[0] = mContentInsetsProvider
                .getBoundingRectForPrivacyChipForRotation(ROTATION_NONE);
                .getBoundingRectForPrivacyChipForRotation(ROTATION_NONE, displayCutout);
        bounds[1] = mContentInsetsProvider
                .getBoundingRectForPrivacyChipForRotation(ROTATION_LANDSCAPE);
                .getBoundingRectForPrivacyChipForRotation(ROTATION_LANDSCAPE, displayCutout);
        bounds[2] = mContentInsetsProvider
                .getBoundingRectForPrivacyChipForRotation(ROTATION_UPSIDE_DOWN);
                .getBoundingRectForPrivacyChipForRotation(ROTATION_UPSIDE_DOWN, displayCutout);
        bounds[3] = mContentInsetsProvider
                .getBoundingRectForPrivacyChipForRotation(ROTATION_SEASCAPE);
                .getBoundingRectForPrivacyChipForRotation(ROTATION_SEASCAPE, displayCutout);

        try {
            mIWindowManager.updateStaticPrivacyIndicatorBounds(mContext.getDisplayId(), bounds);