diff options
| author | 2024-10-16 14:37:02 +0000 | |
|---|---|---|
| committer | 2024-10-17 14:32:15 +0000 | |
| commit | 3dd233d25f5ccd7e8b09370d995dca6c51908b51 (patch) | |
| tree | 4e0a9ee6fd278aa550d803fb1faacff7a9fdef42 | |
| parent | 828f0eb3c14342b941c9262c0aeabbcac8343a9b (diff) | |
Ambient AOD support
Enables transparency on the light reveal scrim, if supported by
the current wallpaper. However, while transitioning from
GONE->AOD, always be fully opaque as the underlying surface is
still visible until the device is fully in AOD.
Bug: 373844670
Test: atest LightRevealScrimInteractorTest
Flag: com.android.systemui.shared.ambient_aod
Change-Id: Iaec877432176d5436d284c00e09c7f985927eeab
13 files changed, 324 insertions, 186 deletions
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractorTest.kt index b6ec6a67b212..e24bb0432ed5 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractorTest.kt @@ -19,6 +19,7 @@ package com.android.systemui.keyguard.domain.interactor import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase +import com.android.systemui.coroutines.collectLastValue import com.android.systemui.coroutines.collectValues import com.android.systemui.keyguard.data.fakeLightRevealScrimRepository import com.android.systemui.keyguard.data.repository.DEFAULT_REVEAL_DURATION @@ -31,7 +32,6 @@ import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.keyguard.shared.model.TransitionStep import com.android.systemui.kosmos.testScope import com.android.systemui.power.data.repository.fakePowerRepository -import com.android.systemui.power.domain.interactor.powerInteractor import com.android.systemui.power.shared.model.WakeSleepReason import com.android.systemui.power.shared.model.WakefulnessState import com.android.systemui.statusbar.LightRevealEffect @@ -98,7 +98,7 @@ class LightRevealScrimInteractorTest : SysuiTestCase() { fakeKeyguardTransitionRepository.sendTransitionStep( TransitionStep( to = KeyguardState.LOCKSCREEN, - transitionState = TransitionState.RUNNING + transitionState = TransitionState.RUNNING, ) ) runCurrent() @@ -110,7 +110,7 @@ class LightRevealScrimInteractorTest : SysuiTestCase() { fakeKeyguardTransitionRepository.sendTransitionStep( TransitionStep( to = KeyguardState.LOCKSCREEN, - transitionState = TransitionState.STARTED + transitionState = TransitionState.STARTED, ) ) runCurrent() @@ -147,19 +147,29 @@ class LightRevealScrimInteractorTest : SysuiTestCase() { assertThat(fakeLightRevealScrimRepository.revealAnimatorRequests.last()) .isEqualTo( - RevealAnimatorRequest( - reveal = false, - duration = DEFAULT_REVEAL_DURATION - ) + RevealAnimatorRequest(reveal = false, duration = DEFAULT_REVEAL_DURATION) ) } + @Test + fun supportsAmbientMode() = + kosmos.testScope.runTest { + val maxAlpha by collectLastValue(underTest.maxAlpha) + assertThat(maxAlpha).isEqualTo(1f) + + underTest.setWallpaperSupportsAmbientMode(true) + assertThat(maxAlpha).isLessThan(1f) + + underTest.setWallpaperSupportsAmbientMode(false) + assertThat(maxAlpha).isEqualTo(1f) + } + private fun updateWakefulness(goToSleepReason: WakeSleepReason) { fakePowerRepository.updateWakefulness( rawState = WakefulnessState.STARTING_TO_SLEEP, lastWakeReason = WakeSleepReason.POWER_BUTTON, lastSleepReason = goToSleepReason, - powerButtonLaunchGestureTriggered = false + powerButtonLaunchGestureTriggered = false, ) } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt index 3230285fcd71..e79f5902575f 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt @@ -32,6 +32,7 @@ import com.android.keyguard.KeyguardStatusView import com.android.keyguard.KeyguardStatusViewController import com.android.keyguard.dagger.KeyguardStatusViewComponent import com.android.systemui.CoreStartable +import com.android.systemui.Flags.lightRevealMigration import com.android.systemui.biometrics.ui.binder.DeviceEntryUnlockTrackerViewBinder import com.android.systemui.common.ui.ConfigurationState import com.android.systemui.dagger.SysUISingleton @@ -42,6 +43,7 @@ import com.android.systemui.keyguard.shared.model.LockscreenSceneBlueprint import com.android.systemui.keyguard.ui.binder.KeyguardBlueprintViewBinder import com.android.systemui.keyguard.ui.binder.KeyguardIndicationAreaBinder import com.android.systemui.keyguard.ui.binder.KeyguardRootViewBinder +import com.android.systemui.keyguard.ui.binder.LightRevealScrimViewBinder import com.android.systemui.keyguard.ui.composable.LockscreenContent import com.android.systemui.keyguard.ui.composable.blueprint.ComposableLockscreenSceneBlueprint import com.android.systemui.keyguard.ui.view.KeyguardIndicationArea @@ -51,6 +53,7 @@ import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel import com.android.systemui.keyguard.ui.viewmodel.KeyguardIndicationAreaViewModel import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel import com.android.systemui.keyguard.ui.viewmodel.KeyguardSmartspaceViewModel +import com.android.systemui.keyguard.ui.viewmodel.LightRevealScrimViewModel import com.android.systemui.keyguard.ui.viewmodel.LockscreenContentViewModel import com.android.systemui.keyguard.ui.viewmodel.OccludingAppDeviceEntryMessageViewModel import com.android.systemui.plugins.FalsingManager @@ -59,11 +62,13 @@ import com.android.systemui.scene.shared.flag.SceneContainerFlag import com.android.systemui.shade.NotificationShadeWindowView import com.android.systemui.shade.domain.interactor.ShadeInteractor import com.android.systemui.statusbar.KeyguardIndicationController +import com.android.systemui.statusbar.LightRevealScrim import com.android.systemui.statusbar.VibratorHelper import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationLockscreenScrimViewModel import com.android.systemui.statusbar.phone.ScreenOffAnimationController import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager import com.android.systemui.temporarydisplay.chipbar.ChipbarCoordinator +import com.android.systemui.wallpapers.ui.viewmodel.WallpaperViewModel import com.google.android.msdl.domain.MSDLPlayer import dagger.Lazy import java.util.Optional @@ -105,6 +110,9 @@ constructor( private val keyguardViewMediator: KeyguardViewMediator, private val deviceEntryUnlockTrackerViewBinder: Optional<DeviceEntryUnlockTrackerViewBinder>, private val statusBarKeyguardViewManager: StatusBarKeyguardViewManager, + private val lightRevealScrimViewModel: LightRevealScrimViewModel, + private val lightRevealScrim: LightRevealScrim, + private val wallpaperViewModel: WallpaperViewModel, @Main private val mainDispatcher: CoroutineDispatcher, private val msdlPlayer: MSDLPlayer, ) : CoreStartable { @@ -133,6 +141,14 @@ constructor( bindKeyguardRootView() initializeViews() + if (lightRevealMigration()) { + LightRevealScrimViewBinder.bind( + lightRevealScrim, + lightRevealScrimViewModel, + wallpaperViewModel, + ) + } + if (!SceneContainerFlag.isEnabled) { KeyguardBlueprintViewBinder.bind( keyguardRootView, diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepository.kt index 0a15bbf18249..4c9c282514cd 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepository.kt @@ -39,6 +39,7 @@ import kotlin.math.max import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.callbackFlow import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.flatMapLatest @@ -65,6 +66,9 @@ interface LightRevealScrimRepository { val isAnimating: Boolean + /** Limit the max alpha for the scrim to allow for some transparency */ + val maxAlpha: MutableStateFlow<Float> + fun startRevealAmountAnimator(reveal: Boolean, duration: Long = DEFAULT_REVEAL_DURATION) } @@ -79,6 +83,7 @@ constructor( ) : LightRevealScrimRepository { companion object { val TAG = LightRevealScrimRepository::class.simpleName!! + val DEFAULT_MAX_ALPHA = 1f } /** The reveal effect used if the device was locked/unlocked via the power button. */ @@ -127,6 +132,8 @@ constructor( private val revealAmountAnimator = ValueAnimator.ofFloat(0f, 1f) + override val maxAlpha: MutableStateFlow<Float> = MutableStateFlow(DEFAULT_MAX_ALPHA) + override val revealAmount: Flow<Float> = callbackFlow { val updateListener = Animator.AnimatorUpdateListener { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractor.kt index 1497026b5750..cf747c81769a 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractor.kt @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +@file:OptIn(ExperimentalCoroutinesApi::class) package com.android.systemui.keyguard.domain.interactor @@ -21,17 +22,22 @@ import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.keyguard.data.repository.DEFAULT_REVEAL_DURATION import com.android.systemui.keyguard.data.repository.LightRevealScrimRepository +import com.android.systemui.keyguard.shared.model.Edge import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.power.domain.interactor.PowerInteractor import com.android.systemui.power.shared.model.ScreenPowerState import com.android.systemui.power.shared.model.WakeSleepReason +import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.statusbar.LightRevealEffect import com.android.systemui.util.kotlin.sample import dagger.Lazy import javax.inject.Inject import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.launch @SysUISingleton @@ -39,7 +45,7 @@ class LightRevealScrimInteractor @Inject constructor( private val transitionInteractor: KeyguardTransitionInteractor, - private val lightRevealScrimRepository: LightRevealScrimRepository, + private val repository: LightRevealScrimRepository, @Application private val scope: CoroutineScope, private val scrimLogger: ScrimLogger, private val powerInteractor: Lazy<PowerInteractor>, @@ -63,17 +69,17 @@ constructor( DEFAULT_REVEAL_DURATION } - lightRevealScrimRepository.startRevealAmountAnimator( + repository.startRevealAmountAnimator( willBeRevealedInState(it.to), - duration = animationDuration + duration = animationDuration, ) } } } private val isLastSleepDueToFold: Boolean - get() = powerInteractor.get().detailedWakefulness.value - .lastSleepReason == WakeSleepReason.FOLD + get() = + powerInteractor.get().detailedWakefulness.value.lastSleepReason == WakeSleepReason.FOLD /** * Whenever a keyguard transition starts, sample the latest reveal effect from the repository @@ -86,12 +92,29 @@ constructor( * LiftReveal. */ val lightRevealEffect: Flow<LightRevealEffect> = - transitionInteractor.startedKeyguardTransitionStep.sample( - lightRevealScrimRepository.revealEffect - ) + transitionInteractor.startedKeyguardTransitionStep.sample(repository.revealEffect) + + /** Limit the max alpha for the scrim to allow for some transparency */ + val maxAlpha: Flow<Float> = + transitionInteractor + .isInTransition( + edge = Edge.create(Scenes.Gone, KeyguardState.AOD), + edgeWithoutSceneContainer = Edge.create(KeyguardState.GONE, KeyguardState.AOD), + ) + .flatMapLatest { isInTransition -> + // During GONE->AOD transitions, the home screen and wallpaper are still visible + // until + // WM is told to hide them, which occurs at the end of the animation. Use an opaque + // scrim until this transition is complete + if (isInTransition) { + flowOf(1f) + } else { + repository.maxAlpha + } + } val revealAmount = - lightRevealScrimRepository.revealAmount.filter { + repository.revealAmount.filter { // When the screen is off we do not want to keep producing frames as this is causing // (invisible) jank. However, we need to still pass through 1f and 0f to ensure that the // correct end states are respected even if the screen turned off (or was still off) @@ -104,7 +127,17 @@ constructor( powerInteractor.get().screenPowerState.value != ScreenPowerState.SCREEN_TURNING_ON val isAnimating: Boolean - get() = lightRevealScrimRepository.isAnimating + get() = repository.isAnimating + + /** If the wallpaper supports ambient mode, allow partial transparency */ + fun setWallpaperSupportsAmbientMode(supportsAmbientMode: Boolean) { + repository.maxAlpha.value = + if (supportsAmbientMode) { + 0.7f + } else { + 1f + } + } /** * Whether the light reveal scrim will be fully revealed (revealAmount = 1.0f) in the given diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/LightRevealScrimViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/LightRevealScrimViewBinder.kt index 2df17c39d90d..32757ce82c69 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/LightRevealScrimViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/LightRevealScrimViewBinder.kt @@ -16,21 +16,49 @@ package com.android.systemui.keyguard.ui.binder +import android.animation.ValueAnimator import androidx.lifecycle.Lifecycle import androidx.lifecycle.repeatOnLifecycle import com.android.app.tracing.coroutines.launchTraced as launch import com.android.systemui.keyguard.ui.viewmodel.LightRevealScrimViewModel import com.android.systemui.lifecycle.repeatWhenAttached +import com.android.systemui.shared.Flags.ambientAod import com.android.systemui.statusbar.LightRevealScrim +import com.android.systemui.wallpapers.ui.viewmodel.WallpaperViewModel import kotlinx.coroutines.launch object LightRevealScrimViewBinder { @JvmStatic - fun bind(revealScrim: LightRevealScrim, viewModel: LightRevealScrimViewModel) { + fun bind( + revealScrim: LightRevealScrim, + viewModel: LightRevealScrimViewModel, + wallpaperViewModel: WallpaperViewModel, + ) { revealScrim.repeatWhenAttached { repeatOnLifecycle(Lifecycle.State.CREATED) { + if (ambientAod()) { + launch("$TAG#wallpaperViewModel.wallpaperSupportsAmbientMode") { + wallpaperViewModel.wallpaperSupportsAmbientMode.collect { + viewModel.setWallpaperSupportsAmbientMode(it) + } + } + launch("$TAG#viewModel.maxAlpha") { + viewModel.maxAlpha.collect { alpha -> + if (alpha != revealScrim.alpha) { + ValueAnimator.ofFloat(revealScrim.alpha, alpha).apply { + duration = 400 + addUpdateListener { animation -> + revealScrim.alpha = animation.getAnimatedValue() as Float + } + start() + } + } + } + } + } + launch("$TAG#viewModel.revealAmount") { - viewModel.revealAmount.collect { amount -> revealScrim.revealAmount = amount } + viewModel.revealAmount.collect { revealScrim.revealAmount = it } } launch("$TAG#viewModel.lightRevealEffect") { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LightRevealScrimViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LightRevealScrimViewModel.kt index 82f40bf3a16a..af6cd166479a 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LightRevealScrimViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LightRevealScrimViewModel.kt @@ -27,7 +27,14 @@ import kotlinx.coroutines.flow.Flow * draw a gradient that reveals/hides the contents of the screen. */ @OptIn(ExperimentalCoroutinesApi::class) -class LightRevealScrimViewModel @Inject constructor(interactor: LightRevealScrimInteractor) { +class LightRevealScrimViewModel +@Inject +constructor(private val interactor: LightRevealScrimInteractor) { val lightRevealEffect: Flow<LightRevealEffect> = interactor.lightRevealEffect val revealAmount: Flow<Float> = interactor.revealAmount + val maxAlpha: Flow<Float> = interactor.maxAlpha + + fun setWallpaperSupportsAmbientMode(supportsAmbientMode: Boolean) { + interactor.setWallpaperSupportsAmbientMode(supportsAmbientMode) + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt index 5c45f3d1bbc8..1db7fb429629 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt @@ -32,14 +32,15 @@ import androidx.annotation.VisibleForTesting import androidx.dynamicanimation.animation.FloatPropertyCompat import androidx.dynamicanimation.animation.SpringAnimation import androidx.dynamicanimation.animation.SpringForce -import com.android.systemui.Dumpable import com.android.app.animation.Interpolators +import com.android.systemui.Dumpable import com.android.systemui.animation.ShadeInterpolation import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dump.DumpManager import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.shade.ShadeExpansionChangeEvent import com.android.systemui.shade.ShadeExpansionListener +import com.android.systemui.shared.Flags.ambientAod import com.android.systemui.statusbar.phone.BiometricUnlockController import com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_WAKE_AND_UNLOCK import com.android.systemui.statusbar.phone.DozeParameters @@ -54,10 +55,13 @@ import kotlin.math.max import kotlin.math.sign /** - * Controller responsible for statusbar window blur. + * Responsible for blurring the notification shade window, and applying a zoom effect to the + * wallpaper. */ @SysUISingleton -class NotificationShadeDepthController @Inject constructor( +class NotificationShadeDepthController +@Inject +constructor( private val statusBarStateController: StatusBarStateController, private val blurUtils: BlurUtils, private val biometricUnlockController: BiometricUnlockController, @@ -69,7 +73,7 @@ class NotificationShadeDepthController @Inject constructor( private val context: Context, private val splitShadeStateController: SplitShadeStateController, dumpManager: DumpManager, - configurationController: ConfigurationController + configurationController: ConfigurationController, ) : ShadeExpansionListener, Dumpable { companion object { private const val WAKE_UP_ANIMATION_ENABLED = true @@ -85,8 +89,7 @@ class NotificationShadeDepthController @Inject constructor( private var keyguardAnimator: Animator? = null private var notificationAnimator: Animator? = null private var updateScheduled: Boolean = false - @VisibleForTesting - var shadeExpansion = 0f + @VisibleForTesting var shadeExpansion = 0f private var isClosed: Boolean = true private var isOpen: Boolean = false private var isBlurred: Boolean = false @@ -106,13 +109,13 @@ class NotificationShadeDepthController @Inject constructor( var shadeAnimation = DepthAnimation() - @VisibleForTesting - var brightnessMirrorSpring = DepthAnimation() + @VisibleForTesting var brightnessMirrorSpring = DepthAnimation() var brightnessMirrorVisible: Boolean = false set(value) { field = value - brightnessMirrorSpring.animateTo(if (value) blurUtils.blurRadiusOfRatio(1f).toInt() - else 0) + brightnessMirrorSpring.animateTo( + if (value) blurUtils.blurRadiusOfRatio(1f).toInt() else 0 + ) } var qsPanelExpansion = 0f @@ -126,9 +129,7 @@ class NotificationShadeDepthController @Inject constructor( scheduleUpdate() } - /** - * How much we're transitioning to the full shade - */ + /** How much we're transitioning to the full shade */ var transitionToFullShadeProgress = 0f set(value) { if (field == value) return @@ -160,19 +161,15 @@ class NotificationShadeDepthController @Inject constructor( shadeAnimation.finishIfRunning() } - /** - * We're unlocking, and should not blur as the panel expansion changes. - */ + /** We're unlocking, and should not blur as the panel expansion changes. */ var blursDisabledForUnlock: Boolean = false - set(value) { - if (field == value) return - field = value - scheduleUpdate() - } + set(value) { + if (field == value) return + field = value + scheduleUpdate() + } - /** - * Force stop blur effect when necessary. - */ + /** Force stop blur effect when necessary. */ private var scrimsVisible: Boolean = false set(value) { if (field == value) return @@ -180,9 +177,7 @@ class NotificationShadeDepthController @Inject constructor( scheduleUpdate() } - /** - * Blur radius of the wake-up animation on this frame. - */ + /** Blur radius of the wake-up animation on this frame. */ private var wakeAndUnlockBlurRadius = 0f set(value) { if (field == value) return @@ -191,15 +186,23 @@ class NotificationShadeDepthController @Inject constructor( } private fun computeBlurAndZoomOut(): Pair<Int, Float> { - val animationRadius = MathUtils.constrain(shadeAnimation.radius, - blurUtils.minBlurRadius.toFloat(), blurUtils.maxBlurRadius.toFloat()) - val expansionRadius = blurUtils.blurRadiusOfRatio( + val animationRadius = + MathUtils.constrain( + shadeAnimation.radius, + blurUtils.minBlurRadius.toFloat(), + blurUtils.maxBlurRadius.toFloat(), + ) + val expansionRadius = + blurUtils.blurRadiusOfRatio( ShadeInterpolation.getNotificationScrimAlpha( - if (shouldApplyShadeBlur()) shadeExpansion else 0f)) - var combinedBlur = (expansionRadius * INTERACTION_BLUR_FRACTION + + if (shouldApplyShadeBlur()) shadeExpansion else 0f + ) + ) + var combinedBlur = + (expansionRadius * INTERACTION_BLUR_FRACTION + animationRadius * ANIMATION_BLUR_FRACTION) - val qsExpandedRatio = ShadeInterpolation.getNotificationScrimAlpha(qsPanelExpansion) * - shadeExpansion + val qsExpandedRatio = + ShadeInterpolation.getNotificationScrimAlpha(qsPanelExpansion) * shadeExpansion combinedBlur = max(combinedBlur, blurUtils.blurRadiusOfRatio(qsExpandedRatio)) combinedBlur = max(combinedBlur, blurUtils.blurRadiusOfRatio(transitionToFullShadeProgress)) var shadeRadius = max(combinedBlur, wakeAndUnlockBlurRadius) @@ -231,83 +234,97 @@ class NotificationShadeDepthController @Inject constructor( return Pair(blur, zoomOut) } - /** - * Callback that updates the window blur value and is called only once per frame. - */ + /** Callback that updates the window blur value and is called only once per frame. */ @VisibleForTesting - val updateBlurCallback = Choreographer.FrameCallback { - updateScheduled = false - val (blur, zoomOut) = computeBlurAndZoomOut() - val opaque = scrimsVisible && !blursDisabledForAppLaunch - Trace.traceCounter(Trace.TRACE_TAG_APP, "shade_blur_radius", blur) - blurUtils.applyBlur(root.viewRootImpl, blur, opaque) - lastAppliedBlur = blur - wallpaperController.setNotificationShadeZoom(zoomOut) - listeners.forEach { - it.onWallpaperZoomOutChanged(zoomOut) - it.onBlurRadiusChanged(blur) - } - notificationShadeWindowController.setBackgroundBlurRadius(blur) - } - - /** - * Animate blurs when unlocking. - */ - private val keyguardStateCallback = object : KeyguardStateController.Callback { - override fun onKeyguardFadingAwayChanged() { - if (!keyguardStateController.isKeyguardFadingAway || - biometricUnlockController.mode != MODE_WAKE_AND_UNLOCK) { - return + val updateBlurCallback = + Choreographer.FrameCallback { + updateScheduled = false + val (blur, zoomOut) = computeBlurAndZoomOut() + val opaque = scrimsVisible && !blursDisabledForAppLaunch + Trace.traceCounter(Trace.TRACE_TAG_APP, "shade_blur_radius", blur) + blurUtils.applyBlur(root.viewRootImpl, blur, opaque) + lastAppliedBlur = blur + wallpaperController.setNotificationShadeZoom(zoomOut) + listeners.forEach { + it.onWallpaperZoomOutChanged(zoomOut) + it.onBlurRadiusChanged(blur) } + notificationShadeWindowController.setBackgroundBlurRadius(blur) + } - keyguardAnimator?.cancel() - keyguardAnimator = ValueAnimator.ofFloat(1f, 0f).apply { - // keyguardStateController.keyguardFadingAwayDuration might be zero when unlock by - // fingerprint due to there is no window container, see AppTransition#goodToGo. - // We use DozeParameters.wallpaperFadeOutDuration as an alternative. - duration = dozeParameters.wallpaperFadeOutDuration - startDelay = keyguardStateController.keyguardFadingAwayDelay - interpolator = Interpolators.FAST_OUT_SLOW_IN - addUpdateListener { animation: ValueAnimator -> - wakeAndUnlockBlurRadius = - blurUtils.blurRadiusOfRatio(animation.animatedValue as Float) + /** Animate blurs when unlocking. */ + private val keyguardStateCallback = + object : KeyguardStateController.Callback { + override fun onKeyguardFadingAwayChanged() { + if ( + !keyguardStateController.isKeyguardFadingAway || + biometricUnlockController.mode != MODE_WAKE_AND_UNLOCK + ) { + return } - addListener(object : AnimatorListenerAdapter() { - override fun onAnimationEnd(animation: Animator) { - keyguardAnimator = null - wakeAndUnlockBlurRadius = 0f + + keyguardAnimator?.cancel() + keyguardAnimator = + ValueAnimator.ofFloat(1f, 0f).apply { + // keyguardStateController.keyguardFadingAwayDuration might be zero when + // unlock by fingerprint due to there is no window container, see + // AppTransition#goodToGo. We use DozeParameters.wallpaperFadeOutDuration as + // an alternative. + duration = dozeParameters.wallpaperFadeOutDuration + startDelay = keyguardStateController.keyguardFadingAwayDelay + interpolator = Interpolators.FAST_OUT_SLOW_IN + addUpdateListener { animation: ValueAnimator -> + wakeAndUnlockBlurRadius = + blurUtils.blurRadiusOfRatio(animation.animatedValue as Float) + } + addListener( + object : AnimatorListenerAdapter() { + override fun onAnimationEnd(animation: Animator) { + keyguardAnimator = null + wakeAndUnlockBlurRadius = 0f + } + } + ) + start() } - }) - start() } - } - override fun onKeyguardShowingChanged() { - if (keyguardStateController.isShowing) { - keyguardAnimator?.cancel() - notificationAnimator?.cancel() + override fun onKeyguardShowingChanged() { + if (keyguardStateController.isShowing) { + keyguardAnimator?.cancel() + notificationAnimator?.cancel() + } } } - } - private val statusBarStateCallback = object : StatusBarStateController.StateListener { - override fun onStateChanged(newState: Int) { - updateShadeAnimationBlur( - shadeExpansion, prevTracking, prevShadeVelocity, prevShadeDirection) - scheduleUpdate() - } + private val statusBarStateCallback = + object : StatusBarStateController.StateListener { + override fun onStateChanged(newState: Int) { + updateShadeAnimationBlur( + shadeExpansion, + prevTracking, + prevShadeVelocity, + prevShadeDirection, + ) + scheduleUpdate() + } - override fun onDozingChanged(isDozing: Boolean) { - if (isDozing) { - shadeAnimation.finishIfRunning() - brightnessMirrorSpring.finishIfRunning() + override fun onDozingChanged(isDozing: Boolean) { + if (isDozing) { + shadeAnimation.finishIfRunning() + brightnessMirrorSpring.finishIfRunning() + } } - } - override fun onDozeAmountChanged(linear: Float, eased: Float) { - wakeAndUnlockBlurRadius = blurUtils.blurRadiusOfRatio(eased) + override fun onDozeAmountChanged(linear: Float, eased: Float) { + wakeAndUnlockBlurRadius = + if (ambientAod()) { + 0f + } else { + blurUtils.blurRadiusOfRatio(eased) + } + } } - } init { dumpManager.registerCriticalDumpable(javaClass.name, this) @@ -317,16 +334,19 @@ class NotificationShadeDepthController @Inject constructor( statusBarStateController.addCallback(statusBarStateCallback) notificationShadeWindowController.setScrimsVisibilityListener { // Stop blur effect when scrims is opaque to avoid unnecessary GPU composition. - visibility -> scrimsVisible = visibility == ScrimController.OPAQUE + visibility -> + scrimsVisible = visibility == ScrimController.OPAQUE } shadeAnimation.setStiffness(SpringForce.STIFFNESS_LOW) shadeAnimation.setDampingRatio(SpringForce.DAMPING_RATIO_NO_BOUNCY) updateResources() - configurationController.addCallback(object : ConfigurationController.ConfigurationListener { - override fun onConfigChanged(newConfig: Configuration?) { - updateResources() + configurationController.addCallback( + object : ConfigurationController.ConfigurationListener { + override fun onConfigChanged(newConfig: Configuration?) { + updateResources() + } } - }) + ) } private fun updateResources() { @@ -341,15 +361,15 @@ class NotificationShadeDepthController @Inject constructor( listeners.remove(listener) } - /** - * Update blurs when pulling down the shade - */ + /** Update blurs when pulling down the shade */ override fun onPanelExpansionChanged(event: ShadeExpansionChangeEvent) { val rawFraction = event.fraction val tracking = event.tracking val timestamp = SystemClock.elapsedRealtimeNanos() - val expansion = MathUtils.saturate( - (rawFraction - panelPullDownMinFraction) / (1f - panelPullDownMinFraction)) + val expansion = + MathUtils.saturate( + (rawFraction - panelPullDownMinFraction) / (1f - panelPullDownMinFraction) + ) if (shadeExpansion == expansion && prevTracking == tracking) { prevTimestamp = timestamp @@ -360,14 +380,14 @@ class NotificationShadeDepthController @Inject constructor( if (prevTimestamp < 0) { prevTimestamp = timestamp } else { - deltaTime = MathUtils.constrain( - ((timestamp - prevTimestamp) / 1E9).toFloat(), 0.00001f, 1f) + deltaTime = + MathUtils.constrain(((timestamp - prevTimestamp) / 1E9).toFloat(), 0.00001f, 1f) } val diff = expansion - shadeExpansion val shadeDirection = sign(diff).toInt() - val shadeVelocity = MathUtils.constrain( - VELOCITY_SCALE * diff / deltaTime, MIN_VELOCITY, MAX_VELOCITY) + val shadeVelocity = + MathUtils.constrain(VELOCITY_SCALE * diff / deltaTime, MIN_VELOCITY, MAX_VELOCITY) updateShadeAnimationBlur(expansion, tracking, shadeVelocity, shadeDirection) prevShadeDirection = shadeDirection @@ -383,7 +403,7 @@ class NotificationShadeDepthController @Inject constructor( expansion: Float, tracking: Boolean, velocity: Float, - direction: Int + direction: Int, ) { if (shouldApplyShadeBlur()) { if (expansion > 0f) { @@ -432,11 +452,12 @@ class NotificationShadeDepthController @Inject constructor( private fun animateBlur(blur: Boolean, velocity: Float) { isBlurred = blur - val targetBlurNormalized = if (blur && shouldApplyShadeBlur()) { - 1f - } else { - 0f - } + val targetBlurNormalized = + if (blur && shouldApplyShadeBlur()) { + 1f + } else { + 0f + } shadeAnimation.setStartVelocity(velocity) shadeAnimation.animateTo(blurUtils.blurRadiusOfRatio(targetBlurNormalized).toInt()) @@ -453,13 +474,13 @@ class NotificationShadeDepthController @Inject constructor( } /** - * Should blur be applied to the shade currently. This is mainly used to make sure that - * on the lockscreen, the wallpaper isn't blurred. + * Should blur be applied to the shade currently. This is mainly used to make sure that on the + * lockscreen, the wallpaper isn't blurred. */ private fun shouldApplyShadeBlur(): Boolean { val state = statusBarStateController.state return (state == StatusBarState.SHADE || state == StatusBarState.SHADE_LOCKED) && - !keyguardStateController.isKeyguardFadingAway + !keyguardStateController.isKeyguardFadingAway } override fun dump(pw: PrintWriter, args: Array<out String>) { @@ -483,33 +504,30 @@ class NotificationShadeDepthController @Inject constructor( * invalidation. */ inner class DepthAnimation() { - /** - * Blur radius visible on the UI, in pixels. - */ + /** Blur radius visible on the UI, in pixels. */ var radius = 0f - /** - * Depth ratio of the current blur radius. - */ + /** Depth ratio of the current blur radius. */ val ratio get() = blurUtils.ratioOfBlurRadius(radius) - /** - * Radius that we're animating to. - */ + /** Radius that we're animating to. */ private var pendingRadius = -1 - private var springAnimation = SpringAnimation(this, object : - FloatPropertyCompat<DepthAnimation>("blurRadius") { - override fun setValue(rect: DepthAnimation?, value: Float) { - radius = value - scheduleUpdate() - } + private var springAnimation = + SpringAnimation( + this, + object : FloatPropertyCompat<DepthAnimation>("blurRadius") { + override fun setValue(rect: DepthAnimation?, value: Float) { + radius = value + scheduleUpdate() + } - override fun getValue(rect: DepthAnimation?): Float { - return radius - } - }) + override fun getValue(rect: DepthAnimation?): Float { + return radius + } + }, + ) init { springAnimation.spring = SpringForce(0.0f) @@ -545,13 +563,9 @@ class NotificationShadeDepthController @Inject constructor( } } - /** - * Invoked when changes are needed in z-space - */ + /** Invoked when changes are needed in z-space */ interface DepthListener { - /** - * Current wallpaper zoom out, where 0 is the closest, and 1 the farthest - */ + /** Current wallpaper zoom out, where 0 is the closest, and 1 the farthest */ fun onWallpaperZoomOutChanged(zoomOut: Float) fun onBlurRadiusChanged(blurRadius: Int) {} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java index 3d7cd9c9fbcd..208486833782 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java @@ -140,8 +140,6 @@ import com.android.systemui.keyguard.KeyguardViewMediator; import com.android.systemui.keyguard.MigrateClocksToBlueprint; import com.android.systemui.keyguard.ScreenLifecycle; import com.android.systemui.keyguard.WakefulnessLifecycle; -import com.android.systemui.keyguard.ui.binder.LightRevealScrimViewBinder; -import com.android.systemui.keyguard.ui.viewmodel.LightRevealScrimViewModel; import com.android.systemui.navigationbar.NavigationBarController; import com.android.systemui.navigationbar.views.NavigationBarView; import com.android.systemui.notetask.NoteTaskController; @@ -425,7 +423,6 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { private final NotificationsController mNotificationsController; private final StatusBarSignalPolicy mStatusBarSignalPolicy; private final StatusBarHideIconsForBouncerManager mStatusBarHideIconsForBouncerManager; - private final Lazy<LightRevealScrimViewModel> mLightRevealScrimViewModelLazy; /** Controller for the Shade. */ private final ShadeSurface mShadeSurface; @@ -698,7 +695,6 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { WiredChargingRippleController wiredChargingRippleController, IDreamManager dreamManager, Lazy<CameraLauncher> cameraLauncherLazy, - Lazy<LightRevealScrimViewModel> lightRevealScrimViewModelLazy, LightRevealScrim lightRevealScrim, AlternateBouncerInteractor alternateBouncerInteractor, UserTracker userTracker, @@ -843,7 +839,6 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { mDeviceStateManager = deviceStateManager; wiredChargingRippleController.registerCallbacks(); - mLightRevealScrimViewModelLazy = lightRevealScrimViewModelLazy; mLightRevealScrim = lightRevealScrim; mViewCaptureAwareWindowManager = viewCaptureAwareWindowManager; @@ -1279,11 +1274,6 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { }); mScrimController.attachViews(scrimBehind, notificationsScrim, scrimInFront); - if (lightRevealMigration()) { - LightRevealScrimViewBinder.bind( - mLightRevealScrim, mLightRevealScrimViewModelLazy.get()); - } - mLightRevealScrim.setScrimOpaqueChangedListener((opaque) -> { Runnable updateOpaqueness = () -> { mNotificationShadeWindowController.setLightRevealScrimOpaque( diff --git a/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/WallpaperRepository.kt b/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/WallpaperRepository.kt index 203e1da2afcf..efdd98d5498a 100644 --- a/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/WallpaperRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/WallpaperRepository.kt @@ -31,6 +31,7 @@ import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.keyguard.data.repository.KeyguardClockRepository import com.android.systemui.keyguard.data.repository.KeyguardRepository +import com.android.systemui.shared.Flags.ambientAod import com.android.systemui.user.data.model.SelectedUserModel import com.android.systemui.user.data.model.SelectionStatus import com.android.systemui.user.data.repository.UserRepository @@ -144,14 +145,21 @@ constructor( override val wallpaperSupportsAmbientMode: StateFlow<Boolean> = wallpaperInfo .map { - // If WallpaperInfo is null, it's ImageWallpaper which never supports ambient mode. - it?.supportsAmbientMode() == true + if (ambientAod()) { + // Force this mode for now, until ImageWallpaper supports it directly + // TODO(b/371236225) + true + } else { + // If WallpaperInfo is null, it's ImageWallpaper which never supports ambient + // mode. + it?.supportsAmbientMode() == true + } } .stateIn( scope, // Always be listening for wallpaper changes. SharingStarted.Eagerly, - initialValue = wallpaperInfo.value?.supportsAmbientMode() == true, + initialValue = if (ambientAod()) true else false, ) override var rootView: View? = null diff --git a/packages/SystemUI/src/com/android/systemui/wallpapers/domain/interactor/WallpaperInteractor.kt b/packages/SystemUI/src/com/android/systemui/wallpapers/domain/interactor/WallpaperInteractor.kt index 79ebf0128d02..fe6977c367b5 100644 --- a/packages/SystemUI/src/com/android/systemui/wallpapers/domain/interactor/WallpaperInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/wallpapers/domain/interactor/WallpaperInteractor.kt @@ -18,9 +18,13 @@ package com.android.systemui.wallpapers.domain.interactor import com.android.systemui.wallpapers.data.repository.WallpaperRepository import javax.inject.Inject +import kotlinx.coroutines.flow.StateFlow class WallpaperInteractor @Inject constructor(val wallpaperRepository: WallpaperRepository) { fun setNotificationStackAbsoluteBottom(bottom: Float) { wallpaperRepository.setNotificationStackAbsoluteBottom(bottom) } + + val wallpaperSupportsAmbientMode: StateFlow<Boolean> = + wallpaperRepository.wallpaperSupportsAmbientMode } diff --git a/packages/SystemUI/src/com/android/systemui/wallpapers/ui/viewmodel/WallpaperViewModel.kt b/packages/SystemUI/src/com/android/systemui/wallpapers/ui/viewmodel/WallpaperViewModel.kt new file mode 100644 index 000000000000..a51acf66432a --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/wallpapers/ui/viewmodel/WallpaperViewModel.kt @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2024 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.wallpapers.ui.viewmodel + +import com.android.systemui.wallpapers.domain.interactor.WallpaperInteractor +import javax.inject.Inject +import kotlinx.coroutines.flow.StateFlow + +class WallpaperViewModel @Inject constructor(interactor: WallpaperInteractor) { + val wallpaperSupportsAmbientMode: StateFlow<Boolean> = interactor.wallpaperSupportsAmbientMode +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java index 44d81a7abfe5..f98d7a91d8fc 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java @@ -123,7 +123,6 @@ import com.android.systemui.keyguard.KeyguardUnlockAnimationController; import com.android.systemui.keyguard.KeyguardViewMediator; import com.android.systemui.keyguard.ScreenLifecycle; import com.android.systemui.keyguard.WakefulnessLifecycle; -import com.android.systemui.keyguard.ui.viewmodel.LightRevealScrimViewModel; import com.android.systemui.kosmos.KosmosJavaAdapter; import com.android.systemui.navigationbar.NavigationBarController; import com.android.systemui.notetask.NoteTaskController; @@ -259,7 +258,6 @@ public class CentralSurfacesImplTest extends SysuiTestCase { @Mock private QuickSettingsController mQuickSettingsController; @Mock private IStatusBarService mBarService; @Mock private IDreamManager mDreamManager; - @Mock private LightRevealScrimViewModel mLightRevealScrimViewModel; @Mock private LightRevealScrim mLightRevealScrim; @Mock private DozeScrimController mDozeScrimController; @Mock private Lazy<BiometricUnlockController> mBiometricUnlockControllerLazy; @@ -604,7 +602,6 @@ public class CentralSurfacesImplTest extends SysuiTestCase { mWiredChargingRippleController, mDreamManager, mCameraLauncherLazy, - () -> mLightRevealScrimViewModel, mLightRevealScrim, mAlternateBouncerInteractor, mUserTracker, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeLightRevealScrimRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeLightRevealScrimRepository.kt index 805a710a2cf3..4181dc302049 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeLightRevealScrimRepository.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeLightRevealScrimRepository.kt @@ -40,6 +40,8 @@ class FakeLightRevealScrimRepository : LightRevealScrimRepository { override val isAnimating: Boolean get() = false + override val maxAlpha: MutableStateFlow<Float> = MutableStateFlow(1f) + override fun startRevealAmountAnimator(reveal: Boolean, duration: Long) { if (reveal) { _revealAmount.value = 1.0f @@ -50,8 +52,5 @@ class FakeLightRevealScrimRepository : LightRevealScrimRepository { revealAnimatorRequests.add(RevealAnimatorRequest(reveal, duration)) } - data class RevealAnimatorRequest( - val reveal: Boolean, - val duration: Long - ) + data class RevealAnimatorRequest(val reveal: Boolean, val duration: Long) } |