diff options
5 files changed, 134 insertions, 30 deletions
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/ClockSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/ClockSection.kt index 0f3fc47d4e91..f021bb6743c4 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/ClockSection.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/ClockSection.kt @@ -16,76 +16,111 @@ package com.android.systemui.keyguard.ui.composable.section -import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.material3.Text +import androidx.compose.foundation.layout.padding import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment +import androidx.compose.runtime.DisposableEffect +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalView +import androidx.compose.ui.res.dimensionResource +import androidx.compose.ui.viewinterop.AndroidView import com.android.compose.animation.scene.ElementKey import com.android.compose.animation.scene.SceneScope +import com.android.compose.modifiers.padding +import com.android.keyguard.KeyguardClockSwitch +import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor import com.android.systemui.keyguard.ui.composable.modifier.onTopPlacementChanged import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel +import com.android.systemui.res.R import javax.inject.Inject class ClockSection @Inject constructor( private val viewModel: KeyguardClockViewModel, + private val clockInteractor: KeyguardClockInteractor, ) { + @Composable fun SceneScope.SmallClock( onTopChanged: (top: Float?) -> Unit, modifier: Modifier = Modifier, ) { - if (viewModel.useLargeClock) { + val clockSize by viewModel.clockSize.collectAsState() + val currentClock by viewModel.currentClock.collectAsState() + viewModel.clock = currentClock + + if (clockSize != KeyguardClockSwitch.SMALL) { onTopChanged(null) return } + if (currentClock?.smallClock?.view == null) { + return + } + + val view = LocalView.current + + DisposableEffect(view) { + clockInteractor.clockEventController.registerListeners(view) + + onDispose { clockInteractor.clockEventController.unregisterListeners() } + } + MovableElement( key = ClockElementKey, modifier = modifier, ) { content { - Box( + AndroidView( + factory = { checkNotNull(currentClock).smallClock.view }, modifier = - Modifier.fillMaxWidth() - .background(Color.Magenta) - .onTopPlacementChanged(onTopChanged) - ) { - Text( - text = "TODO(b/316211368): Small clock", - color = Color.White, - modifier = Modifier.align(Alignment.Center), - ) - } + Modifier.padding( + horizontal = + dimensionResource(R.dimen.keyguard_affordance_horizontal_offset) + ) + .padding(top = { viewModel.getSmallClockTopMargin(view.context) }) + .onTopPlacementChanged(onTopChanged), + ) } } } @Composable fun SceneScope.LargeClock(modifier: Modifier = Modifier) { - if (!viewModel.useLargeClock) { + val clockSize by viewModel.clockSize.collectAsState() + val currentClock by viewModel.currentClock.collectAsState() + viewModel.clock = currentClock + + if (clockSize != KeyguardClockSwitch.LARGE) { return } + if (currentClock?.largeClock?.view == null) { + return + } + + val view = LocalView.current + + DisposableEffect(view) { + clockInteractor.clockEventController.registerListeners(view) + + onDispose { clockInteractor.clockEventController.unregisterListeners() } + } + MovableElement( key = ClockElementKey, modifier = modifier, ) { content { - Box( - modifier = Modifier.fillMaxWidth().background(Color.Blue), - ) { - Text( - text = "TODO(b/316211368): Large clock", - color = Color.White, - modifier = Modifier.align(Alignment.Center), - ) - } + AndroidView( + factory = { checkNotNull(currentClock).largeClock.view }, + modifier = + Modifier.fillMaxWidth() + .padding(top = { viewModel.getLargeClockTopMargin(view.context) }) + ) } } } diff --git a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt index bcc20448297d..82410fd39dcd 100644 --- a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt +++ b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt @@ -33,6 +33,7 @@ import android.view.ViewTreeObserver.OnGlobalLayoutListener import androidx.annotation.VisibleForTesting import androidx.lifecycle.Lifecycle import androidx.lifecycle.repeatOnLifecycle +import com.android.systemui.Flags.migrateClocksToBlueprint import com.android.systemui.broadcast.BroadcastDispatcher import com.android.systemui.customization.R import com.android.systemui.dagger.qualifiers.Background @@ -325,6 +326,10 @@ constructor( } } + if (visible) { + refreshTime() + } + smallTimeListener?.update(shouldTimeListenerRun) largeTimeListener?.update(shouldTimeListenerRun) } @@ -346,6 +351,19 @@ constructor( weatherData = data clock?.run { events.onWeatherDataChanged(data) } } + + override fun onTimeChanged() { + refreshTime() + } + + private fun refreshTime() { + if (!migrateClocksToBlueprint()) { + return + } + + clock?.smallClock?.events?.onTimeTick() + clock?.largeClock?.events?.onTimeTick() + } } private val zenModeCallback = object : ZenModeController.Callback { @@ -558,7 +576,8 @@ constructor( isRunning = true when (clockFace.config.tickRate) { ClockTickRate.PER_MINUTE -> { - /* Handled by KeyguardClockSwitchController */ + // Handled by KeyguardClockSwitchController and + // by KeyguardUpdateMonitorCallback#onTimeChanged. } ClockTickRate.PER_SECOND -> executor.execute(secondsRunnable) ClockTickRate.PER_FRAME -> { 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 528a2eebc9cd..5bb27824753d 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 @@ -16,6 +16,7 @@ package com.android.systemui.keyguard.ui.viewmodel +import android.content.Context import androidx.constraintlayout.helper.widget.Layer import com.android.keyguard.KeyguardClockSwitch.LARGE import com.android.keyguard.KeyguardClockSwitch.SMALL @@ -25,6 +26,9 @@ import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor import com.android.systemui.keyguard.shared.model.SettingsClockSize import com.android.systemui.plugins.clocks.ClockController +import com.android.systemui.res.R +import com.android.systemui.statusbar.policy.SplitShadeStateController +import com.android.systemui.util.Utils import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.SharingStarted @@ -36,9 +40,10 @@ import kotlinx.coroutines.flow.stateIn class KeyguardClockViewModel @Inject constructor( - val keyguardInteractor: KeyguardInteractor, - val keyguardClockInteractor: KeyguardClockInteractor, + keyguardInteractor: KeyguardInteractor, + private val keyguardClockInteractor: KeyguardClockInteractor, @Application private val applicationScope: CoroutineScope, + private val splitShadeStateController: SplitShadeStateController, ) { var burnInLayer: Layer? = null val useLargeClock: Boolean @@ -85,4 +90,43 @@ constructor( started = SharingStarted.WhileSubscribed(), initialValue = false ) + + // Needs to use a non application context to get display cutout. + fun getSmallClockTopMargin(context: Context) = + if (splitShadeStateController.shouldUseSplitNotificationShade(context.resources)) { + context.resources.getDimensionPixelSize(R.dimen.keyguard_split_shade_top_margin) + } else { + context.resources.getDimensionPixelSize(R.dimen.keyguard_clock_top_margin) + + Utils.getStatusBarHeaderHeightKeyguard(context) + } + + fun getLargeClockTopMargin(context: Context): Int { + var largeClockTopMargin = + context.resources.getDimensionPixelSize(R.dimen.status_bar_height) + + context.resources.getDimensionPixelSize( + com.android.systemui.customization.R.dimen.small_clock_padding_top + ) + + context.resources.getDimensionPixelSize(R.dimen.keyguard_smartspace_top_offset) + largeClockTopMargin += getDimen(context, DATE_WEATHER_VIEW_HEIGHT) + largeClockTopMargin += getDimen(context, ENHANCED_SMARTSPACE_HEIGHT) + if (!useLargeClock) { + largeClockTopMargin -= + context.resources.getDimensionPixelSize( + com.android.systemui.customization.R.dimen.small_clock_height + ) + } + + return largeClockTopMargin + } + + private fun getDimen(context: Context, name: String): Int { + val res = context.packageManager.getResourcesForApplication(context.packageName) + val id = res.getIdentifier(name, "dimen", context.packageName) + return res.getDimensionPixelSize(id) + } + + companion object { + private const val DATE_WEATHER_VIEW_HEIGHT = "date_weather_view_height" + private const val ENHANCED_SMARTSPACE_HEIGHT = "enhanced_smartspace_height" + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelTest.kt index d4210040faf3..1b4573dafe5e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelTest.kt @@ -34,6 +34,7 @@ import com.android.systemui.plugins.clocks.ClockController import com.android.systemui.plugins.clocks.ClockFaceConfig import com.android.systemui.plugins.clocks.ClockFaceController import com.android.systemui.shared.clocks.ClockRegistry +import com.android.systemui.statusbar.policy.SplitShadeStateController import com.android.systemui.util.mockito.whenever import com.android.systemui.util.settings.FakeSettings import com.google.common.truth.Truth.assertThat @@ -66,6 +67,8 @@ class KeyguardClockViewModelTest : SysuiTestCase() { @Mock private lateinit var largeClock: ClockFaceController @Mock private lateinit var clockFaceConfig: ClockFaceConfig @Mock private lateinit var eventController: ClockEventController + @Mock private lateinit var splitShadeStateController: SplitShadeStateController + @Before fun setup() { MockitoAnnotations.initMocks(this) @@ -92,6 +95,7 @@ class KeyguardClockViewModelTest : SysuiTestCase() { keyguardInteractor, keyguardClockInteractor, scope.backgroundScope, + splitShadeStateController, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelKosmos.kt index d8786830f536..5ca0439c1313 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelKosmos.kt @@ -20,6 +20,7 @@ import com.android.systemui.keyguard.domain.interactor.keyguardClockInteractor import com.android.systemui.keyguard.domain.interactor.keyguardInteractor import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.applicationCoroutineScope +import com.android.systemui.statusbar.policy.splitShadeStateController val Kosmos.keyguardClockViewModel by Kosmos.Fixture { @@ -27,5 +28,6 @@ val Kosmos.keyguardClockViewModel by keyguardInteractor = keyguardInteractor, keyguardClockInteractor = keyguardClockInteractor, applicationScope = applicationCoroutineScope, + splitShadeStateController = splitShadeStateController, ) } |