Loading packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/ViewBasedLockscreenContent.kt +6 −4 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ import androidx.compose.ui.viewinterop.AndroidView import androidx.core.view.isVisible import com.android.compose.animation.scene.SceneScope import com.android.systemui.keyguard.qualifiers.KeyguardRootView import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel import com.android.systemui.keyguard.ui.viewmodel.LockscreenSceneViewModel import com.android.systemui.notifications.ui.composable.NotificationStack import com.android.systemui.res.R Loading @@ -47,8 +48,9 @@ import javax.inject.Inject class ViewBasedLockscreenContent @Inject constructor( private val viewModel: LockscreenSceneViewModel, private val lockscreenSceneViewModel: LockscreenSceneViewModel, @KeyguardRootView private val viewProvider: () -> @JvmSuppressWildcards View, private val keyguardRootViewModel: KeyguardRootViewModel, ) { @Composable fun SceneScope.Content( Loading @@ -59,7 +61,7 @@ constructor( } LockscreenLongPress( viewModel = viewModel.longPress, viewModel = lockscreenSceneViewModel.longPress, modifier = modifier, ) { onSettingsMenuPlaced -> AndroidView( Loading @@ -74,7 +76,7 @@ constructor( ) val notificationStackPosition by viewModel.keyguardRoot.notificationBounds.collectAsState() keyguardRootViewModel.notificationBounds.collectAsState() Layout( modifier = Loading @@ -92,7 +94,7 @@ constructor( }, content = { NotificationStack( viewModel = viewModel.notifications, viewModel = lockscreenSceneViewModel.notifications, isScrimVisible = false, ) } Loading packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/BurnInState.kt 0 → 100644 +94 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.systemui.keyguard.ui.composable.blueprint import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.displayCutout import androidx.compose.foundation.layout.systemBars import androidx.compose.foundation.layout.union import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.platform.LocalDensity import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor import com.android.systemui.keyguard.ui.viewmodel.BurnInParameters import com.android.systemui.plugins.clocks.ClockController import kotlin.math.min import kotlin.math.roundToInt /** Produces a [BurnInState] that can be used to query the `LockscreenBurnInViewModel` flows. */ @Composable fun rememberBurnIn( clockInteractor: KeyguardClockInteractor, ): BurnInState { val clock by clockInteractor.currentClock.collectAsState() val (smartspaceTop, onSmartspaceTopChanged) = remember { mutableStateOf<Float?>(null) } val (smallClockTop, onSmallClockTopChanged) = remember { mutableStateOf<Float?>(null) } val topmostTop = when { smartspaceTop != null && smallClockTop != null -> min(smartspaceTop, smallClockTop) smartspaceTop != null -> smartspaceTop smallClockTop != null -> smallClockTop else -> 0f }.roundToInt() val params = rememberBurnInParameters(clock, topmostTop) return remember(params, onSmartspaceTopChanged, onSmallClockTopChanged) { BurnInState( parameters = params, onSmartspaceTopChanged = onSmartspaceTopChanged, onSmallClockTopChanged = onSmallClockTopChanged, ) } } @Composable private fun rememberBurnInParameters( clock: ClockController?, topmostTop: Int, ): BurnInParameters { val density = LocalDensity.current val topInset = WindowInsets.systemBars.union(WindowInsets.displayCutout).getTop(density) return remember(clock, topInset, topmostTop) { BurnInParameters( clockControllerProvider = { clock }, topInset = topInset, statusViewTop = topmostTop, ) } } data class BurnInState( /** Parameters for use with the `LockscreenBurnInViewModel. */ val parameters: BurnInParameters, /** * Callback to invoke when the top coordinate of the smartspace element is updated, pass `null` * when the element is not shown. */ val onSmartspaceTopChanged: (Float?) -> Unit, /** * Callback to invoke when the top coordinate of the small clock element is updated, pass `null` * when the element is not shown. */ val onSmallClockTopChanged: (Float?) -> Unit, ) packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt +16 −2 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.layout.Layout import androidx.compose.ui.unit.IntRect import com.android.compose.animation.scene.SceneScope import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor import com.android.systemui.keyguard.ui.composable.LockscreenLongPress import com.android.systemui.keyguard.ui.composable.section.AmbientIndicationSection import com.android.systemui.keyguard.ui.composable.section.BottomAreaSection Loading Loading @@ -55,6 +56,7 @@ constructor( private val ambientIndicationSection: AmbientIndicationSection, private val bottomAreaSection: BottomAreaSection, private val settingsMenuSection: SettingsMenuSection, private val clockInteractor: KeyguardClockInteractor, ) : LockscreenSceneBlueprint { override val id: String = "default" Loading @@ -62,6 +64,7 @@ constructor( @Composable override fun SceneScope.Content(modifier: Modifier) { val isUdfpsVisible = viewModel.isUdfpsVisible val burnIn = rememberBurnIn(clockInteractor) LockscreenLongPress( viewModel = viewModel.longPress, Loading @@ -74,8 +77,19 @@ constructor( modifier = Modifier.fillMaxWidth(), ) { with(statusBarSection) { StatusBar(modifier = Modifier.fillMaxWidth()) } with(clockSection) { SmallClock(modifier = Modifier.fillMaxWidth()) } with(smartSpaceSection) { SmartSpace(modifier = Modifier.fillMaxWidth()) } with(clockSection) { SmallClock( onTopChanged = burnIn.onSmallClockTopChanged, modifier = Modifier.fillMaxWidth(), ) } with(smartSpaceSection) { SmartSpace( burnInParams = burnIn.parameters, onTopChanged = burnIn.onSmartspaceTopChanged, modifier = Modifier.fillMaxWidth(), ) } with(clockSection) { LargeClock(modifier = Modifier.fillMaxWidth()) } with(notificationSection) { Notifications(modifier = Modifier.fillMaxWidth().weight(1f)) Loading packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/ShortcutsBesideUdfpsBlueprint.kt +16 −2 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.layout.Layout import androidx.compose.ui.unit.IntRect import com.android.compose.animation.scene.SceneScope import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor import com.android.systemui.keyguard.ui.composable.LockscreenLongPress import com.android.systemui.keyguard.ui.composable.section.AmbientIndicationSection import com.android.systemui.keyguard.ui.composable.section.BottomAreaSection Loading Loading @@ -55,6 +56,7 @@ constructor( private val ambientIndicationSection: AmbientIndicationSection, private val bottomAreaSection: BottomAreaSection, private val settingsMenuSection: SettingsMenuSection, private val clockInteractor: KeyguardClockInteractor, ) : LockscreenSceneBlueprint { override val id: String = "shortcuts-besides-udfps" Loading @@ -62,6 +64,7 @@ constructor( @Composable override fun SceneScope.Content(modifier: Modifier) { val isUdfpsVisible = viewModel.isUdfpsVisible val burnIn = rememberBurnIn(clockInteractor) LockscreenLongPress( viewModel = viewModel.longPress, Loading @@ -74,8 +77,19 @@ constructor( modifier = Modifier.fillMaxWidth(), ) { with(statusBarSection) { StatusBar(modifier = Modifier.fillMaxWidth()) } with(clockSection) { SmallClock(modifier = Modifier.fillMaxWidth()) } with(smartSpaceSection) { SmartSpace(modifier = Modifier.fillMaxWidth()) } with(clockSection) { SmallClock( onTopChanged = burnIn.onSmallClockTopChanged, modifier = Modifier.fillMaxWidth(), ) } with(smartSpaceSection) { SmartSpace( burnInParams = burnIn.parameters, onTopChanged = burnIn.onSmartspaceTopChanged, modifier = Modifier.fillMaxWidth(), ) } with(clockSection) { LargeClock(modifier = Modifier.fillMaxWidth()) } with(notificationSection) { Notifications(modifier = Modifier.fillMaxWidth().weight(1f)) Loading packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/modifier/BurnInModifiers.kt 0 → 100644 +68 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.systemui.keyguard.ui.composable.modifier import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.layout.boundsInWindow import androidx.compose.ui.layout.onPlaced import com.android.systemui.keyguard.ui.viewmodel.AodBurnInViewModel import com.android.systemui.keyguard.ui.viewmodel.BurnInParameters import com.android.systemui.keyguard.ui.viewmodel.BurnInScaleViewModel /** * Modifies the composable to account for anti-burn in translation, alpha, and scaling. * * Please override [isClock] as `true` if the composable is an element that's part of a clock. */ @Composable fun Modifier.burnInAware( viewModel: AodBurnInViewModel, params: BurnInParameters, isClock: Boolean = false, ): Modifier { val translationX by viewModel.translationX(params).collectAsState(initial = 0f) val translationY by viewModel.translationY(params).collectAsState(initial = 0f) val alpha by viewModel.alpha.collectAsState(initial = 1f) val scaleViewModel by viewModel.scale(params).collectAsState(initial = BurnInScaleViewModel()) return this.graphicsLayer { val scale = when { scaleViewModel.scaleClockOnly && isClock -> scaleViewModel.scale !scaleViewModel.scaleClockOnly -> scaleViewModel.scale else -> 1f } this.translationX = translationX this.translationY = translationY this.alpha = alpha this.scaleX = scale this.scaleY = scale } } /** Reports the "top" coordinate of the modified composable to the given [consumer]. */ @Composable fun Modifier.onTopPlacementChanged( consumer: (Float) -> Unit, ): Modifier { return onPlaced { coordinates -> consumer(coordinates.boundsInWindow().top) } } Loading
packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/ViewBasedLockscreenContent.kt +6 −4 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ import androidx.compose.ui.viewinterop.AndroidView import androidx.core.view.isVisible import com.android.compose.animation.scene.SceneScope import com.android.systemui.keyguard.qualifiers.KeyguardRootView import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel import com.android.systemui.keyguard.ui.viewmodel.LockscreenSceneViewModel import com.android.systemui.notifications.ui.composable.NotificationStack import com.android.systemui.res.R Loading @@ -47,8 +48,9 @@ import javax.inject.Inject class ViewBasedLockscreenContent @Inject constructor( private val viewModel: LockscreenSceneViewModel, private val lockscreenSceneViewModel: LockscreenSceneViewModel, @KeyguardRootView private val viewProvider: () -> @JvmSuppressWildcards View, private val keyguardRootViewModel: KeyguardRootViewModel, ) { @Composable fun SceneScope.Content( Loading @@ -59,7 +61,7 @@ constructor( } LockscreenLongPress( viewModel = viewModel.longPress, viewModel = lockscreenSceneViewModel.longPress, modifier = modifier, ) { onSettingsMenuPlaced -> AndroidView( Loading @@ -74,7 +76,7 @@ constructor( ) val notificationStackPosition by viewModel.keyguardRoot.notificationBounds.collectAsState() keyguardRootViewModel.notificationBounds.collectAsState() Layout( modifier = Loading @@ -92,7 +94,7 @@ constructor( }, content = { NotificationStack( viewModel = viewModel.notifications, viewModel = lockscreenSceneViewModel.notifications, isScrimVisible = false, ) } Loading
packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/BurnInState.kt 0 → 100644 +94 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.systemui.keyguard.ui.composable.blueprint import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.displayCutout import androidx.compose.foundation.layout.systemBars import androidx.compose.foundation.layout.union import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.platform.LocalDensity import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor import com.android.systemui.keyguard.ui.viewmodel.BurnInParameters import com.android.systemui.plugins.clocks.ClockController import kotlin.math.min import kotlin.math.roundToInt /** Produces a [BurnInState] that can be used to query the `LockscreenBurnInViewModel` flows. */ @Composable fun rememberBurnIn( clockInteractor: KeyguardClockInteractor, ): BurnInState { val clock by clockInteractor.currentClock.collectAsState() val (smartspaceTop, onSmartspaceTopChanged) = remember { mutableStateOf<Float?>(null) } val (smallClockTop, onSmallClockTopChanged) = remember { mutableStateOf<Float?>(null) } val topmostTop = when { smartspaceTop != null && smallClockTop != null -> min(smartspaceTop, smallClockTop) smartspaceTop != null -> smartspaceTop smallClockTop != null -> smallClockTop else -> 0f }.roundToInt() val params = rememberBurnInParameters(clock, topmostTop) return remember(params, onSmartspaceTopChanged, onSmallClockTopChanged) { BurnInState( parameters = params, onSmartspaceTopChanged = onSmartspaceTopChanged, onSmallClockTopChanged = onSmallClockTopChanged, ) } } @Composable private fun rememberBurnInParameters( clock: ClockController?, topmostTop: Int, ): BurnInParameters { val density = LocalDensity.current val topInset = WindowInsets.systemBars.union(WindowInsets.displayCutout).getTop(density) return remember(clock, topInset, topmostTop) { BurnInParameters( clockControllerProvider = { clock }, topInset = topInset, statusViewTop = topmostTop, ) } } data class BurnInState( /** Parameters for use with the `LockscreenBurnInViewModel. */ val parameters: BurnInParameters, /** * Callback to invoke when the top coordinate of the smartspace element is updated, pass `null` * when the element is not shown. */ val onSmartspaceTopChanged: (Float?) -> Unit, /** * Callback to invoke when the top coordinate of the small clock element is updated, pass `null` * when the element is not shown. */ val onSmallClockTopChanged: (Float?) -> Unit, )
packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt +16 −2 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.layout.Layout import androidx.compose.ui.unit.IntRect import com.android.compose.animation.scene.SceneScope import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor import com.android.systemui.keyguard.ui.composable.LockscreenLongPress import com.android.systemui.keyguard.ui.composable.section.AmbientIndicationSection import com.android.systemui.keyguard.ui.composable.section.BottomAreaSection Loading Loading @@ -55,6 +56,7 @@ constructor( private val ambientIndicationSection: AmbientIndicationSection, private val bottomAreaSection: BottomAreaSection, private val settingsMenuSection: SettingsMenuSection, private val clockInteractor: KeyguardClockInteractor, ) : LockscreenSceneBlueprint { override val id: String = "default" Loading @@ -62,6 +64,7 @@ constructor( @Composable override fun SceneScope.Content(modifier: Modifier) { val isUdfpsVisible = viewModel.isUdfpsVisible val burnIn = rememberBurnIn(clockInteractor) LockscreenLongPress( viewModel = viewModel.longPress, Loading @@ -74,8 +77,19 @@ constructor( modifier = Modifier.fillMaxWidth(), ) { with(statusBarSection) { StatusBar(modifier = Modifier.fillMaxWidth()) } with(clockSection) { SmallClock(modifier = Modifier.fillMaxWidth()) } with(smartSpaceSection) { SmartSpace(modifier = Modifier.fillMaxWidth()) } with(clockSection) { SmallClock( onTopChanged = burnIn.onSmallClockTopChanged, modifier = Modifier.fillMaxWidth(), ) } with(smartSpaceSection) { SmartSpace( burnInParams = burnIn.parameters, onTopChanged = burnIn.onSmartspaceTopChanged, modifier = Modifier.fillMaxWidth(), ) } with(clockSection) { LargeClock(modifier = Modifier.fillMaxWidth()) } with(notificationSection) { Notifications(modifier = Modifier.fillMaxWidth().weight(1f)) Loading
packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/ShortcutsBesideUdfpsBlueprint.kt +16 −2 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.layout.Layout import androidx.compose.ui.unit.IntRect import com.android.compose.animation.scene.SceneScope import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor import com.android.systemui.keyguard.ui.composable.LockscreenLongPress import com.android.systemui.keyguard.ui.composable.section.AmbientIndicationSection import com.android.systemui.keyguard.ui.composable.section.BottomAreaSection Loading Loading @@ -55,6 +56,7 @@ constructor( private val ambientIndicationSection: AmbientIndicationSection, private val bottomAreaSection: BottomAreaSection, private val settingsMenuSection: SettingsMenuSection, private val clockInteractor: KeyguardClockInteractor, ) : LockscreenSceneBlueprint { override val id: String = "shortcuts-besides-udfps" Loading @@ -62,6 +64,7 @@ constructor( @Composable override fun SceneScope.Content(modifier: Modifier) { val isUdfpsVisible = viewModel.isUdfpsVisible val burnIn = rememberBurnIn(clockInteractor) LockscreenLongPress( viewModel = viewModel.longPress, Loading @@ -74,8 +77,19 @@ constructor( modifier = Modifier.fillMaxWidth(), ) { with(statusBarSection) { StatusBar(modifier = Modifier.fillMaxWidth()) } with(clockSection) { SmallClock(modifier = Modifier.fillMaxWidth()) } with(smartSpaceSection) { SmartSpace(modifier = Modifier.fillMaxWidth()) } with(clockSection) { SmallClock( onTopChanged = burnIn.onSmallClockTopChanged, modifier = Modifier.fillMaxWidth(), ) } with(smartSpaceSection) { SmartSpace( burnInParams = burnIn.parameters, onTopChanged = burnIn.onSmartspaceTopChanged, modifier = Modifier.fillMaxWidth(), ) } with(clockSection) { LargeClock(modifier = Modifier.fillMaxWidth()) } with(notificationSection) { Notifications(modifier = Modifier.fillMaxWidth().weight(1f)) Loading
packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/modifier/BurnInModifiers.kt 0 → 100644 +68 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.systemui.keyguard.ui.composable.modifier import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.layout.boundsInWindow import androidx.compose.ui.layout.onPlaced import com.android.systemui.keyguard.ui.viewmodel.AodBurnInViewModel import com.android.systemui.keyguard.ui.viewmodel.BurnInParameters import com.android.systemui.keyguard.ui.viewmodel.BurnInScaleViewModel /** * Modifies the composable to account for anti-burn in translation, alpha, and scaling. * * Please override [isClock] as `true` if the composable is an element that's part of a clock. */ @Composable fun Modifier.burnInAware( viewModel: AodBurnInViewModel, params: BurnInParameters, isClock: Boolean = false, ): Modifier { val translationX by viewModel.translationX(params).collectAsState(initial = 0f) val translationY by viewModel.translationY(params).collectAsState(initial = 0f) val alpha by viewModel.alpha.collectAsState(initial = 1f) val scaleViewModel by viewModel.scale(params).collectAsState(initial = BurnInScaleViewModel()) return this.graphicsLayer { val scale = when { scaleViewModel.scaleClockOnly && isClock -> scaleViewModel.scale !scaleViewModel.scaleClockOnly -> scaleViewModel.scale else -> 1f } this.translationX = translationX this.translationY = translationY this.alpha = alpha this.scaleX = scale this.scaleY = scale } } /** Reports the "top" coordinate of the modified composable to the given [consumer]. */ @Composable fun Modifier.onTopPlacementChanged( consumer: (Float) -> Unit, ): Modifier { return onPlaced { coordinates -> consumer(coordinates.boundsInWindow().top) } }