diff options
author | 2025-02-19 17:39:42 +0000 | |
---|---|---|
committer | 2025-02-26 18:42:47 +0000 | |
commit | 6ab1439415117af5e4ed361889507bc6614a9c6d (patch) | |
tree | 687acd99b45ebfc61cf3c9653ee4b4ca138f4191 | |
parent | fd356738abe400daebc08bdc151d36e177c4bc8d (diff) |
Update smartspace positions on doze amount change
Bug: 372246519
Test: Manually confirmed view moves correctly
Flag: com.android.systemui.shared.clock_reactive_smartspace_layout
Change-Id: I1eadd0eaea77c701cf300b6bef9091d7bfbd5533
16 files changed, 146 insertions, 49 deletions
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ComposedDigitalLayerController.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ComposedDigitalLayerController.kt index b9200c15944c..e9e61a718f08 100644 --- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ComposedDigitalLayerController.kt +++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ComposedDigitalLayerController.kt @@ -44,6 +44,7 @@ class ComposedDigitalLayerController(private val clockCtx: ClockContext) : val dozeState = DefaultClockController.AnimationState(1F) override val view = FlexClockView(clockCtx) + override var onViewBoundsChanged by view::onViewBoundsChanged init { fun createController(cfg: LayerConfig) { diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt index f24ad1c10c4a..9bb3bac824e9 100644 --- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt +++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt @@ -17,6 +17,7 @@ import android.content.Context import android.content.res.Resources import android.graphics.Color import android.graphics.Rect +import android.graphics.RectF import android.icu.text.NumberFormat import android.util.TypedValue import android.view.LayoutInflater @@ -97,7 +98,12 @@ class DefaultClockController( events.onLocaleChanged(Locale.getDefault()) } - override fun initialize(isDarkTheme: Boolean, dozeFraction: Float, foldFraction: Float) { + override fun initialize( + isDarkTheme: Boolean, + dozeFraction: Float, + foldFraction: Float, + onBoundsChanged: (RectF) -> Unit, + ) { largeClock.recomputePadding(null) largeClock.animations = LargeClockAnimations(largeClock.view, dozeFraction, foldFraction) diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockController.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockController.kt index 1a1033ba42e0..6dfd2268005f 100644 --- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockController.kt +++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockController.kt @@ -16,6 +16,7 @@ package com.android.systemui.shared.clocks +import android.graphics.RectF import com.android.systemui.animation.GSFAxes import com.android.systemui.customization.R import com.android.systemui.plugins.clocks.AlarmData @@ -102,9 +103,15 @@ class FlexClockController(private val clockCtx: ClockContext) : ClockController } } - override fun initialize(isDarkTheme: Boolean, dozeFraction: Float, foldFraction: Float) { + override fun initialize( + isDarkTheme: Boolean, + dozeFraction: Float, + foldFraction: Float, + onBoundsChanged: (RectF) -> Unit, + ) { events.onFontAxesChanged(clockCtx.settings.axes) smallClock.run { + layerController.onViewBoundsChanged = onBoundsChanged events.onThemeChanged(theme.copy(isDarkTheme = isDarkTheme)) animations.doze(dozeFraction) animations.fold(foldFraction) @@ -112,6 +119,7 @@ class FlexClockController(private val clockCtx: ClockContext) : ClockController } largeClock.run { + layerController.onViewBoundsChanged = onBoundsChanged events.onThemeChanged(theme.copy(isDarkTheme = isDarkTheme)) animations.doze(dozeFraction) animations.fold(foldFraction) diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleClockLayerController.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleClockLayerController.kt index af00cc264208..336c66eed889 100644 --- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleClockLayerController.kt +++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleClockLayerController.kt @@ -16,6 +16,7 @@ package com.android.systemui.shared.clocks +import android.graphics.RectF import android.view.View import androidx.annotation.VisibleForTesting import com.android.systemui.plugins.clocks.ClockAnimations @@ -31,4 +32,5 @@ interface SimpleClockLayerController { val config: ClockFaceConfig @VisibleForTesting var fakeTimeMills: Long? + var onViewBoundsChanged: ((RectF) -> Unit)? } diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleDigitalHandLayerController.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleDigitalHandLayerController.kt index 0b7ea1a335ef..97004ef6f9a9 100644 --- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleDigitalHandLayerController.kt +++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleDigitalHandLayerController.kt @@ -85,6 +85,7 @@ open class SimpleDigitalHandLayerController( override val view = SimpleDigitalClockTextView(clockCtx, isLargeClock) private val logger = Logger(clockCtx.messageBuffer, TAG) val timespec = DigitalTimespecHandler(layerCfg.timespec, layerCfg.dateTimeFormat) + override var onViewBoundsChanged by view::onViewBoundsChanged @VisibleForTesting override var fakeTimeMills: Long? diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/FlexClockView.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/FlexClockView.kt index 2d0ca5331299..c765ea9cc84c 100644 --- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/FlexClockView.kt +++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/FlexClockView.kt @@ -100,6 +100,7 @@ class FlexClockView(clockCtx: ClockContext) : ViewGroup(clockCtx.context) { updateLocale(Locale.getDefault()) } + var onViewBoundsChanged: ((RectF) -> Unit)? = null private val digitOffsets = mutableMapOf<Int, Float>() protected fun calculateSize( @@ -189,13 +190,21 @@ class FlexClockView(clockCtx: ClockContext) : ViewGroup(clockCtx.context) { fun updateLocation() { val layoutBounds = this.layoutBounds ?: return + val bounds = + RectF( + layoutBounds.centerX() - measuredWidth / 2f, + layoutBounds.centerY() - measuredHeight / 2f, + layoutBounds.centerX() + measuredWidth / 2f, + layoutBounds.centerY() + measuredHeight / 2f, + ) setFrame( - (layoutBounds.centerX() - measuredWidth / 2f).roundToInt(), - (layoutBounds.centerY() - measuredHeight / 2f).roundToInt(), - (layoutBounds.centerX() + measuredWidth / 2f).roundToInt(), - (layoutBounds.centerY() + measuredHeight / 2f).roundToInt(), + bounds.left.roundToInt(), + bounds.top.roundToInt(), + bounds.right.roundToInt(), + bounds.bottom.roundToInt(), ) updateChildFrames(isLayout = false) + onViewBoundsChanged?.let { it(bounds) } } override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextView.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextView.kt index 015a82707ea2..5aea88de061c 100644 --- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextView.kt +++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextView.kt @@ -117,6 +117,7 @@ open class SimpleDigitalClockTextView( fidgetFontVariation = buildFidgetVariation(lsFontAxes).toFVar() } + var onViewBoundsChanged: ((RectF) -> Unit)? = null private val parser = DimensionParser(clockCtx.context) var maxSingleDigitHeight = -1f var maxSingleDigitWidth = -1f @@ -497,6 +498,7 @@ open class SimpleDigitalClockTextView( targetRect.right.roundToInt(), targetRect.bottom.roundToInt(), ) + onViewBoundsChanged?.let { it(targetRect) } return targetRect } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/clocks/DefaultClockProviderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/clocks/DefaultClockProviderTest.kt index 9eba410ffdb5..4f301031e77c 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/clocks/DefaultClockProviderTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/clocks/DefaultClockProviderTest.kt @@ -108,7 +108,7 @@ class DefaultClockProviderTest : SysuiTestCase() { verify(mockSmallClockView).setColors(DOZE_COLOR, Color.MAGENTA) verify(mockLargeClockView).setColors(DOZE_COLOR, Color.MAGENTA) - clock.initialize(true, 0f, 0f) + clock.initialize(true, 0f, 0f, {}) val expectedColor = 0 verify(mockSmallClockView).setColors(DOZE_COLOR, expectedColor) diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockController.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockController.kt index 32fec3277f18..4c1f6450dd78 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockController.kt +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockController.kt @@ -13,6 +13,7 @@ */ package com.android.systemui.plugins.clocks +import android.graphics.RectF import com.android.systemui.plugins.annotations.ProtectedInterface import com.android.systemui.plugins.annotations.SimpleProperty import java.io.PrintWriter @@ -37,7 +38,12 @@ interface ClockController { val events: ClockEvents /** Initializes various rendering parameters. If never called, provides reasonable defaults. */ - fun initialize(isDarkTheme: Boolean, dozeFraction: Float, foldFraction: Float) + fun initialize( + isDarkTheme: Boolean, + dozeFraction: Float, + foldFraction: Float, + onBoundsChanged: (RectF) -> Unit, + ) /** Optional method for dumping debug information */ fun dump(pw: PrintWriter) diff --git a/packages/SystemUI/res-keyguard/values/dimens.xml b/packages/SystemUI/res-keyguard/values/dimens.xml index 6d446453d9f7..24fd86076d64 100644 --- a/packages/SystemUI/res-keyguard/values/dimens.xml +++ b/packages/SystemUI/res-keyguard/values/dimens.xml @@ -115,6 +115,7 @@ <dimen name="below_clock_padding_end">16dp</dimen> <dimen name="below_clock_padding_start_icons">28dp</dimen> <dimen name="smartspace_padding_horizontal">16dp</dimen> + <dimen name="smartspace_padding_vertical">12dp</dimen> <!-- Proportion of the screen height to use to set the maximum height of the bouncer to when the device is in the DEVICE_POSTURE_HALF_OPENED posture, for the PIN/pattern entry. 0 will diff --git a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt index 1b8282bf9b93..94342349e727 100644 --- a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt +++ b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt @@ -21,6 +21,7 @@ import android.content.Context import android.content.Intent import android.content.IntentFilter import android.content.res.Resources +import android.graphics.RectF import android.os.Trace import android.provider.Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS import android.provider.Settings.Global.ZEN_MODE_OFF @@ -78,7 +79,7 @@ import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.DisposableHandle import kotlinx.coroutines.Job -import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.merge @@ -147,7 +148,7 @@ constructor( val clockStr = clock.toString() loggers.forEach { it.d({ "New Clock: $str1" }) { str1 = clockStr } } - clock.initialize(isDarkTheme(), dozeAmount, 0f) + clock.initialize(isDarkTheme(), dozeAmount.value, 0f, { onClockBoundsChanged.value = it }) if (!regionSamplingEnabled) { updateColors() @@ -240,17 +241,16 @@ constructor( private var smallClockFrame: ViewGroup? = null private var onGlobalLayoutListener: OnGlobalLayoutListener? = null - private var isDozing = false - private set - private var isCharging = false - private var dozeAmount = 0f private var isKeyguardVisible = false private var isRegistered = false private var disposableHandle: DisposableHandle? = null private val regionSamplingEnabled = featureFlags.isEnabled(REGION_SAMPLING) private var largeClockOnSecondaryDisplay = false + val dozeAmount = MutableStateFlow(0f) + val onClockBoundsChanged = MutableStateFlow<RectF?>(null) + private fun isDarkTheme(): Boolean { val isLightTheme = TypedValue() context.theme.resolveAttribute(android.R.attr.isLightTheme, isLightTheme, true) @@ -306,7 +306,7 @@ constructor( var smallTimeListener: TimeListener? = null var largeTimeListener: TimeListener? = null val shouldTimeListenerRun: Boolean - get() = isKeyguardVisible && dozeAmount < DOZE_TICKRATE_THRESHOLD + get() = isKeyguardVisible && dozeAmount.value < DOZE_TICKRATE_THRESHOLD private var weatherData: WeatherData? = null private var zenData: ZenData? = null @@ -466,7 +466,6 @@ constructor( disposableHandle = parent.repeatWhenAttached { repeatOnLifecycle(Lifecycle.State.CREATED) { - listenForDozing(this) if (ModesUi.isEnabled) { listenForDnd(this) } @@ -576,17 +575,17 @@ constructor( } private fun handleDoze(doze: Float) { - dozeAmount = doze clock?.run { Trace.beginSection("$TAG#smallClock.animations.doze") - smallClock.animations.doze(dozeAmount) + smallClock.animations.doze(doze) Trace.endSection() Trace.beginSection("$TAG#largeClock.animations.doze") - largeClock.animations.doze(dozeAmount) + largeClock.animations.doze(doze) Trace.endSection() } smallTimeListener?.update(doze < DOZE_TICKRATE_THRESHOLD) largeTimeListener?.update(doze < DOZE_TICKRATE_THRESHOLD) + dozeAmount.value = doze } @VisibleForTesting @@ -642,18 +641,6 @@ constructor( } } - @VisibleForTesting - internal fun listenForDozing(scope: CoroutineScope): Job { - return scope.launch { - combine(keyguardInteractor.dozeAmount, keyguardInteractor.isDozing) { - localDozeAmount, - localIsDozing -> - localDozeAmount > dozeAmount || localIsDozing - } - .collect { localIsDozing -> isDozing = localIsDozing } - } - } - class TimeListener(val clockFace: ClockFaceController, val executor: DelayableExecutor) { val predrawListener = ViewTreeObserver.OnPreDrawListener { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractor.kt index 63cf4f72e415..ab0efed2cb76 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractor.kt @@ -85,7 +85,7 @@ constructor( val previewClock: Flow<ClockController> = keyguardClockRepository.previewClock - val clockEventController: ClockEventController by keyguardClockRepository::clockEventController + val clockEventController: ClockEventController = keyguardClockRepository.clockEventController var clock: ClockController? by keyguardClockRepository.clockEventController::clock diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSmartspaceViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSmartspaceViewBinder.kt index def1ac8742da..e81d5354ec6e 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSmartspaceViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSmartspaceViewBinder.kt @@ -81,22 +81,92 @@ object KeyguardSmartspaceViewBinder { } if (com.android.systemui.shared.Flags.clockReactiveSmartspaceLayout()) { + val xBuffer = + keyguardRootView.context.resources.getDimensionPixelSize( + R.dimen.smartspace_padding_horizontal + ) + val yBuffer = + keyguardRootView.context.resources.getDimensionPixelSize( + R.dimen.smartspace_padding_vertical + ) + + val smallViewIds = + listOf(sharedR.id.date_smartspace_view, sharedR.id.weather_smartspace_view) + + val largeViewIds = + listOf( + sharedR.id.date_smartspace_view_large, + sharedR.id.weather_smartspace_view_large, + ) + launch("$TAG#smartspaceViewModel.burnInLayerVisibility") { - keyguardRootViewModel.burnInLayerVisibility.collect { visibility -> - if (clockViewModel.isLargeClockVisible.value) { - // hide small clock date/weather - val dateView = - keyguardRootView.requireViewById<View>( - sharedR.id.date_smartspace_view - ) - dateView.visibility = View.GONE - val weatherView = - keyguardRootView.requireViewById<View>( - sharedR.id.weather_smartspace_view - ) - weatherView.visibility = View.GONE + combine( + keyguardRootViewModel.burnInLayerVisibility, + clockViewModel.isLargeClockVisible, + ::Pair, + ) + .collect { (visibility, isLargeClock) -> + if (isLargeClock) { + // hide small clock date/weather + for (viewId in smallViewIds) { + keyguardRootView.findViewById<View>(viewId)?.let { + it.visibility = View.GONE + } + } + } + } + } + + launch("$TAG#clockEventController.onClockBoundsChanged") { + // Whenever the doze amount changes, the clock may update it's view bounds. + // We need to update our layout position as a result. We could do this via + // `requestLayout`, but that's quite expensive when enclosed in since this + // recomputes the entire ConstraintLayout, so instead we do it manually. We + // would use translationX/Y for this, but that's used by burnin. + combine( + clockViewModel.isLargeClockVisible, + clockViewModel.clockEventController.onClockBoundsChanged, + ::Pair, + ) + .collect { (isLargeClock, clockBounds) -> + for (id in (if (isLargeClock) smallViewIds else largeViewIds)) { + keyguardRootView.findViewById<View>(id)?.let { + it.visibility = View.GONE + } + } + + if (clockBounds == null) return@collect + if (isLargeClock) { + val largeDateHeight = + keyguardRootView + .findViewById<View>( + sharedR.id.date_smartspace_view_large + ) + ?.height ?: 0 + for (id in largeViewIds) { + keyguardRootView.findViewById<View>(id)?.let { view -> + val viewHeight = view.height + val offset = (largeDateHeight - viewHeight) / 2 + view.top = + (clockBounds.bottom + yBuffer + offset).toInt() + view.bottom = view.top + viewHeight + } + } + } else { + for (id in smallViewIds) { + keyguardRootView.findViewById<View>(id)?.let { view -> + val viewWidth = view.width + if (view.isLayoutRtl()) { + view.right = (clockBounds.left - xBuffer).toInt() + view.left = view.right - viewWidth + } else { + view.left = (clockBounds.right + xBuffer).toInt() + view.right = view.left + viewWidth + } + } + } + } } - } } } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSection.kt index 37cc852ffe00..d0b5f743c277 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSection.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSection.kt @@ -226,7 +226,7 @@ constructor( ConstraintSet.TOP, customR.id.lockscreen_clock_view_large, ConstraintSet.BOTTOM, - dateWeatherPaddingStart, + context.resources.getDimensionPixelSize(R.dimen.smartspace_padding_vertical), ) connect( @@ -291,7 +291,9 @@ constructor( ConstraintSet.START, customR.id.lockscreen_clock_view, ConstraintSet.END, - 20, + context.resources.getDimensionPixelSize( + R.dimen.smartspace_padding_horizontal + ), ) connect( sharedR.id.date_smartspace_view, diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModel.kt index cf5cc264be8d..dcbf7b5a9335 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModel.kt @@ -19,6 +19,7 @@ package com.android.systemui.keyguard.ui.viewmodel import android.content.Context import android.content.res.Resources import androidx.constraintlayout.helper.widget.Layer +import com.android.keyguard.ClockEventController import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor import com.android.systemui.customization.R as customR import com.android.systemui.dagger.SysUISingleton @@ -68,6 +69,7 @@ constructor( initialValue = true, ) + val clockEventController: ClockEventController = keyguardClockInteractor.clockEventController val currentClock = keyguardClockInteractor.currentClock val hasCustomWeatherDataDisplay = diff --git a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt index f822ee97807e..f18d73d57f83 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt @@ -194,7 +194,7 @@ class ClockEventControllerTest : SysuiTestCase() { @Test fun clockSet_validateInitialization() { - verify(clock).initialize(any(), anyFloat(), anyFloat()) + verify(clock).initialize(any(), anyFloat(), anyFloat(), any()) } @Test |