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 Original line Diff line number Diff line
@@ -53,6 +53,8 @@ public class PhoneStatusBarView extends FrameLayout {
    private View mCutoutSpace;
    private View mCutoutSpace;
    @Nullable
    @Nullable
    private DisplayCutout mDisplayCutout;
    private DisplayCutout mDisplayCutout;
    @Nullable
    private Rect mDisplaySize;
    private int mStatusBarHeight;
    private int mStatusBarHeight;
    @Nullable
    @Nullable
    private TouchEventHandler mTouchEventHandler;
    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.
        // Always have Battery meters in the status bar observe the dark/light modes.
        Dependency.get(DarkIconDispatcher.class).addDarkReceiver(mBattery);
        Dependency.get(DarkIconDispatcher.class).addDarkReceiver(mBattery);
        Dependency.get(DarkIconDispatcher.class).addDarkReceiver(mClock);
        Dependency.get(DarkIconDispatcher.class).addDarkReceiver(mClock);
        if (updateOrientationAndCutout()) {
        if (updateDisplayParameters()) {
            updateLayoutForCutout();
            updateLayoutForCutout();
        }
        }
    }
    }
@@ -106,7 +108,7 @@ public class PhoneStatusBarView extends FrameLayout {
        updateResources();
        updateResources();


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


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


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

        return changed;
        return changed;
    }
    }


+38 −26
Original line number Original line 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.Rotation
import com.android.systemui.util.leak.RotationUtils.getExactRotation
import com.android.systemui.util.leak.RotationUtils.getExactRotation
import com.android.systemui.util.leak.RotationUtils.getResourcesForRotation
import com.android.systemui.util.leak.RotationUtils.getResourcesForRotation
import com.android.systemui.util.traceSection


import java.io.PrintWriter
import java.io.PrintWriter
import java.lang.Math.max
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
     *      (i.e., ROTATION_NONE will always return the same bounds regardless of the context
     *      from which this method is called)
     *      from which this method is called)
     */
     */
    fun getBoundingRectForPrivacyChipForRotation(@Rotation rotation: Int): Rect {
    fun getBoundingRectForPrivacyChipForRotation(@Rotation rotation: Int,
        var insets = insetsCache[getCacheKey(rotation = rotation)]
                                                 displayCutout: DisplayCutout?): Rect {
        val key = getCacheKey(rotation, displayCutout)
        var insets = insetsCache[key]
        if (insets == null) {
        if (insets == null) {
            insets = getStatusBarContentAreaForRotation(rotation)
            insets = getStatusBarContentAreaForRotation(rotation)
        }
        }
@@ -156,19 +159,22 @@ class StatusBarContentInsetsProvider @Inject constructor(
     *
     *
     * @param rotation the target rotation for which to calculate insets
     * @param rotation the target rotation for which to calculate insets
     */
     */
    fun getStatusBarContentInsetsForRotation(@Rotation rotation: Int): Pair<Int, Int> {
    fun getStatusBarContentInsetsForRotation(@Rotation rotation: Int): Pair<Int, Int> =
        val key = getCacheKey(rotation)
        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
            // Target rotation can be a different orientation than the current device rotation
            point.orientToRotZero(getExactRotation(context))
            point.orientToRotZero(getExactRotation(context))
            val width = point.logicalWidth(rotation)
            val width = point.logicalWidth(rotation)


            val area = insetsCache[key] ?: getAndSetCalculatedAreaForRotation(
            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(
    fun getStatusBarContentAreaForRotation(
        @Rotation rotation: Int
        @Rotation rotation: Int
    ): Rect {
    ): Rect {
        val key = getCacheKey(rotation)
        val displayCutout = context.display.cutout
        val key = getCacheKey(rotation, displayCutout)
        return insetsCache[key] ?: getAndSetCalculatedAreaForRotation(
        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(
    private fun getAndSetCalculatedAreaForRotation(
        @Rotation targetRotation: Int,
        @Rotation targetRotation: Int,
        displayCutout: DisplayCutout?,
        rotatedResources: Resources,
        rotatedResources: Resources,
        key: CacheKey
        key: CacheKey
    ): Rect {
    ): Rect {
        return getCalculatedAreaForRotation(targetRotation, rotatedResources)
        return getCalculatedAreaForRotation(displayCutout, targetRotation, rotatedResources)
                .also {
                .also {
                    insetsCache.put(key, it)
                    insetsCache.put(key, it)
                }
                }
    }
    }


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


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


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


    private data class CacheKey(
    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.
 * 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 sbHeight appropriate status bar height for this rotation
 * @param width display width calculated for ROTATION_NONE
 * @param width display width calculated for ROTATION_NONE
 * @param height display height calculated for ROTATION_NONE
 * @param height display height calculated for ROTATION_NONE
@@ -386,7 +398,7 @@ fun calculateInsetsForRotationWithRotatedResources(
 * rotation
 * rotation
 */
 */
private fun getStatusBarLeftRight(
private fun getStatusBarLeftRight(
    dc: DisplayCutout?,
    displayCutout: DisplayCutout?,
    sbHeight: Int,
    sbHeight: Int,
    width: Int,
    width: Int,
    height: Int,
    height: Int,
@@ -402,7 +414,7 @@ private fun getStatusBarLeftRight(


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


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


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


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


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