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
This commit is contained in:
@@ -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,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,20 +159,23 @@ 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 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 screenBounds = context.resources.configuration.windowConfiguration.maxBounds
|
||||
val point = Point(screenBounds.width(), screenBounds.height())
|
||||
|
||||
val area = insetsCache[key] ?: getAndSetCalculatedAreaForRotation(
|
||||
rotation, getResourcesForRotation(rotation, context), key)
|
||||
// Target rotation can be a different orientation than the current device rotation
|
||||
point.orientToRotZero(getExactRotation(context))
|
||||
val width = point.logicalWidth(rotation)
|
||||
|
||||
return Pair(area.left, width - area.right)
|
||||
}
|
||||
val area = insetsCache[key] ?: getAndSetCalculatedAreaForRotation(
|
||||
rotation, displayCutout, getResourcesForRotation(rotation, context), key)
|
||||
|
||||
Pair(area.left, width - area.right)
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the left and right insets for the status bar content in the device's current
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user