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

Commit 298837c0 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Fix ShadeHeader flickers due to insets and corner radius when the...

Merge "Fix ShadeHeader flickers due to insets and corner radius when the window moves display" into main
parents 10f0f245 80cb86ab
Loading
Loading
Loading
Loading
+55 −13
Original line number Diff line number Diff line
@@ -16,31 +16,43 @@

package com.android.systemui.common.ui.compose.windowinsets

import android.content.Context
import android.graphics.Point
import android.view.WindowInsets
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.getValue
import androidx.compose.runtime.ProvidableCompositionLocal
import androidx.compose.runtime.State
import androidx.compose.runtime.remember
import androidx.compose.runtime.staticCompositionLocalOf
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import kotlinx.coroutines.flow.StateFlow
import com.android.internal.policy.ScreenDecorationsUtils

/** The bounds and [CutoutLocation] of the current display. */
val LocalDisplayCutout = staticCompositionLocalOf { DisplayCutout() }
/**
 * The bounds and [CutoutLocation] of the current display.
 *
 * This is provided as a [State] and not as a simple [DisplayCutout] as the cutout is calculated
 * from insets and can change after recomposition but before layout. If a plain DisplayCutout was
 * provided and the value was read during recomposition, it would result in a frame using the wrong
 * value after new insets are received.
 */
val LocalDisplayCutout: ProvidableCompositionLocal<() -> DisplayCutout> = staticCompositionLocalOf {
    { DisplayCutout() }
}

/** The corner radius in px of the current display. */
val LocalScreenCornerRadius = staticCompositionLocalOf { 0.dp }

@Composable
fun ScreenDecorProvider(
    displayCutout: StateFlow<DisplayCutout>,
    screenCornerRadius: StateFlow<Float>,
    content: @Composable () -> Unit,
) {
    val cutout by displayCutout.collectAsStateWithLifecycle()
    val screenCornerRadiusPx by screenCornerRadius.collectAsStateWithLifecycle()

fun ScreenDecorProvider(windowInsets: () -> WindowInsets?, content: @Composable () -> Unit) {
    val context = LocalContext.current
    val screenCornerRadiusPx =
        remember(context.display.uniqueId) { ScreenDecorationsUtils.getWindowCornerRadius(context) }
    val screenCornerRadiusDp = with(LocalDensity.current) { screenCornerRadiusPx.toDp() }
    val cutout = remember(windowInsets, context) { { windowInsets().toCutout(context) } }

    CompositionLocalProvider(
        LocalScreenCornerRadius provides screenCornerRadiusDp,
@@ -49,3 +61,33 @@ fun ScreenDecorProvider(
        content()
    }
}

private fun WindowInsets?.toCutout(context: Context): DisplayCutout {
    val boundingRect = this?.displayCutout?.boundingRectTop
    val width = boundingRect?.let { boundingRect.right - boundingRect.left } ?: 0
    val left = boundingRect?.left?.toDp(context) ?: 0.dp
    val top = boundingRect?.top?.toDp(context) ?: 0.dp
    val right = boundingRect?.right?.toDp(context) ?: 0.dp
    val bottom = boundingRect?.bottom?.toDp(context) ?: 0.dp
    val location =
        when {
            width <= 0f -> CutoutLocation.NONE
            left <= 0.dp -> CutoutLocation.LEFT
            right >= getDisplayWidth(context) -> CutoutLocation.RIGHT
            else -> CutoutLocation.CENTER
        }
    val viewDisplayCutout = this?.displayCutout
    return DisplayCutout(left, top, right, bottom, location, viewDisplayCutout)
}

// TODO(b/298525212): remove once Compose exposes window inset bounds.
private fun Int.toDp(context: Context): Dp {
    return (this.toFloat() / context.resources.displayMetrics.density).dp
}

// TODO(b/298525212): remove once Compose exposes window inset bounds.
private fun getDisplayWidth(context: Context): Dp {
    val point = Point()
    checkNotNull(context.display).getRealSize(point)
    return point.x.toDp(context)
}
+2 −1
Original line number Diff line number Diff line
@@ -66,7 +66,8 @@ constructor(
    @Composable
    fun StatusBar(modifier: Modifier = Modifier) {
        val context = LocalContext.current
        val viewDisplayCutout = LocalDisplayCutout.current.viewDisplayCutoutKeyguardStatusBarView
        val viewDisplayCutout =
            LocalDisplayCutout.current().viewDisplayCutoutKeyguardStatusBarView

        @SuppressLint("InflateParams")
        val view =
+1 −2
Original line number Diff line number Diff line
@@ -64,7 +64,6 @@ import androidx.compose.ui.layout.layoutId
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.unit.IntOffset
@@ -195,7 +194,7 @@ private fun ContentScope.QuickSettingsScene(
    shadeSession: SaveableSession,
    jankMonitor: InteractionJankMonitor,
) {
    val cutoutLocation = LocalDisplayCutout.current.location
    val cutoutLocation = LocalDisplayCutout.current().location
    val brightnessMirrorShowing by brightnessMirrorViewModel.isShowing.collectAsStateWithLifecycle()
    val contentAlpha by
        animateFloatAsState(
+10 −7
Original line number Diff line number Diff line
@@ -184,7 +184,7 @@ fun ContentScope.CollapsedShadeHeader(
    isSplitShade: Boolean,
    modifier: Modifier = Modifier,
) {
    val cutoutLocation = LocalDisplayCutout.current.location
    val cutoutLocation = LocalDisplayCutout.current().location
    val horizontalPadding =
        max(LocalScreenCornerRadius.current / 2f, Shade.Dimensions.HorizontalPadding)

@@ -461,16 +461,19 @@ private fun CutoutAwareShadeHeader(
    startContent: @Composable () -> Unit,
    endContent: @Composable () -> Unit,
) {
    val cutoutWidth = LocalDisplayCutout.current.width()
    val cutoutHeight = LocalDisplayCutout.current.height()
    val cutoutTop = LocalDisplayCutout.current.top
    val cutoutLocation = LocalDisplayCutout.current.location
    val cutoutProvider = LocalDisplayCutout.current
    val statusBarHeight = ShadeHeader.Dimensions.StatusBarHeight

    Layout(
        modifier = modifier.sysuiResTag(ShadeHeader.TestTags.Root),
        contents = listOf(startContent, endContent),
    ) { measurables, constraints ->
        val cutout = cutoutProvider()

        val cutoutWidth = cutout.width()
        val cutoutHeight = cutout.height()
        val cutoutTop = cutout.top
        val cutoutLocation = cutout.location

        check(constraints.hasBoundedWidth)
        check(measurables.size == 2)
        check(measurables[0].size == 1)
@@ -595,7 +598,7 @@ private fun BatteryIconLegacy(
    val inverseColor =
        Utils.getColorAttrDefaultColor(themedContext, android.R.attr.textColorPrimaryInverse)

    val cutoutLocation = LocalDisplayCutout.current.location
    val cutoutLocation = LocalDisplayCutout.current().location

    AndroidView(
        factory = { context ->
+2 −2
Original line number Diff line number Diff line
@@ -92,8 +92,8 @@ import com.android.systemui.media.dagger.MediaModule.QUICK_QS_PANEL
import com.android.systemui.notifications.ui.composable.NotificationScrollingStack
import com.android.systemui.notifications.ui.composable.NotificationStackCutoffGuideline
import com.android.systemui.qs.footer.ui.compose.FooterActionsWithAnimatedVisibility
import com.android.systemui.qs.ui.composable.BrightnessMirror
import com.android.systemui.qs.panels.ui.compose.QuickQuickSettings
import com.android.systemui.qs.ui.composable.BrightnessMirror
import com.android.systemui.qs.ui.composable.QuickSettings
import com.android.systemui.qs.ui.composable.QuickSettings.SharedValues.MediaLandscapeTopOffset
import com.android.systemui.res.R
@@ -250,7 +250,7 @@ private fun ContentScope.SingleShade(
    shadeSession: SaveableSession,
    usingCollapsedLandscapeMedia: Boolean,
) {
    val cutoutLocation = LocalDisplayCutout.current.location
    val cutoutLocation = LocalDisplayCutout.current().location
    val cutoutInsets = WindowInsets.Companion.displayCutout
    mediaHost.expansion = if (usingCollapsedLandscapeMedia && isLandscape()) COLLAPSED else EXPANDED

Loading