Loading packages/SystemUI/compose/features/src/com/android/systemui/common/ui/compose/windowinsets/ScreenDecorProvider.kt +55 −13 Original line number Diff line number Diff line Loading @@ -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, Loading @@ -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) } packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/element/StatusBarElement.kt +2 −1 Original line number Diff line number Diff line Loading @@ -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 = Loading packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt +1 −2 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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( Loading packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt +10 −7 Original line number Diff line number Diff line Loading @@ -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) Loading Loading @@ -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) Loading Loading @@ -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 -> Loading packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt +2 −2 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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 Loading
packages/SystemUI/compose/features/src/com/android/systemui/common/ui/compose/windowinsets/ScreenDecorProvider.kt +55 −13 Original line number Diff line number Diff line Loading @@ -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, Loading @@ -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) }
packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/element/StatusBarElement.kt +2 −1 Original line number Diff line number Diff line Loading @@ -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 = Loading
packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt +1 −2 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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( Loading
packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt +10 −7 Original line number Diff line number Diff line Loading @@ -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) Loading Loading @@ -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) Loading Loading @@ -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 -> Loading
packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt +2 −2 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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