Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 395090de authored by Sherry Zhou's avatar Sherry Zhou
Browse files

Fix clock can be gone in wallpaper picker multi crop preview by creating a new...

Fix clock can be gone in wallpaper picker multi crop preview by creating a new clock instance for each previewRenderer

Flag: ACONFIG com.android.systemui.migrate_clocks_to_blueprint STAGING
ACONFIG com.android.wallpaper.multi_crop_preview_ui_flag TEAMFOOD
Bug: 327668072
Test: manual

Change-Id: I216cf50d012cbaa787f6a5ba3943d5f2fc453795
parent 43526e4c
Loading
Loading
Loading
Loading
+27 −28
Original line number Diff line number Diff line
@@ -18,7 +18,6 @@ package com.android.systemui.keyguard.data.repository

import android.os.UserHandle
import android.provider.Settings
import androidx.annotation.VisibleForTesting
import com.android.keyguard.ClockEventController
import com.android.keyguard.KeyguardClockSwitch.ClockSize
import com.android.keyguard.KeyguardClockSwitch.LARGE
@@ -52,14 +51,14 @@ interface KeyguardClockRepository {
    val clockSize: StateFlow<Int>

    /** clock size selected in picker, DYNAMIC or SMALL */
    val selectedClockSize: Flow<SettingsClockSize>
    val selectedClockSize: StateFlow<SettingsClockSize>

    /** clock id, selected from clock carousel in wallpaper picker */
    val currentClockId: Flow<ClockId>

    val currentClock: StateFlow<ClockController?>

    val previewClockPair: StateFlow<Pair<ClockController, ClockController>>
    val previewClock: Flow<ClockController>

    val clockEventController: ClockEventController
    fun setClockSize(@ClockSize size: Int)
@@ -84,14 +83,19 @@ constructor(
        _clockSize.value = size
    }

    override val selectedClockSize: Flow<SettingsClockSize> =
    override val selectedClockSize: StateFlow<SettingsClockSize> =
        secureSettings
            .observerFlow(
                names = arrayOf(Settings.Secure.LOCKSCREEN_USE_DOUBLE_LINE_CLOCK),
                userId = UserHandle.USER_SYSTEM,
            )
            .onStart { emit(Unit) } // Forces an initial update.
            .map { getClockSize() }
            .map { withContext(backgroundDispatcher) { getClockSize() } }
            .stateIn(
                scope = applicationScope,
                started = SharingStarted.WhileSubscribed(),
                initialValue = getClockSize()
            )

    override val currentClockId: Flow<ClockId> =
        callbackFlow {
@@ -123,20 +127,16 @@ constructor(
                initialValue = clockRegistry.createCurrentClock()
            )

    override val previewClockPair: StateFlow<Pair<ClockController, ClockController>> =
        currentClockId
            .map { Pair(clockRegistry.createCurrentClock(), clockRegistry.createCurrentClock()) }
            .stateIn(
                scope = applicationScope,
                started = SharingStarted.WhileSubscribed(),
                initialValue =
                    Pair(clockRegistry.createCurrentClock(), clockRegistry.createCurrentClock())
            )
    override val previewClock: Flow<ClockController> =
        currentClockId.map {
            // We should create a new instance for each collect call
            // cause in preview, the same clock will be attached to different view
            // at the same time
            clockRegistry.createCurrentClock()
        }

    @VisibleForTesting
    suspend fun getClockSize(): SettingsClockSize {
        return withContext(backgroundDispatcher) {
            if (
    private fun getClockSize(): SettingsClockSize {
        return if (
            secureSettings.getIntForUser(
                Settings.Secure.LOCKSCREEN_USE_DOUBLE_LINE_CLOCK,
                1,
@@ -149,4 +149,3 @@ constructor(
        }
    }
}
}
+2 −3
Original line number Diff line number Diff line
@@ -38,14 +38,13 @@ constructor(
    private val keyguardClockRepository: KeyguardClockRepository,
) {

    val selectedClockSize: Flow<SettingsClockSize> = keyguardClockRepository.selectedClockSize
    val selectedClockSize: StateFlow<SettingsClockSize> = keyguardClockRepository.selectedClockSize

    val currentClockId: Flow<ClockId> = keyguardClockRepository.currentClockId

    val currentClock: StateFlow<ClockController?> = keyguardClockRepository.currentClock

    val previewClockPair: StateFlow<Pair<ClockController, ClockController>> =
        keyguardClockRepository.previewClockPair
    val previewClock: Flow<ClockController> = keyguardClockRepository.previewClock

    var clock: ClockController? by keyguardClockRepository.clockEventController::clock

+26 −48
Original line number Diff line number Diff line
@@ -32,7 +32,6 @@ import androidx.constraintlayout.widget.ConstraintSet.TOP
import androidx.core.view.isVisible
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
import com.android.keyguard.ClockEventController
import com.android.systemui.customization.R as customizationR
import com.android.systemui.keyguard.shared.model.SettingsClockSize
import com.android.systemui.keyguard.ui.preview.KeyguardPreviewRenderer
@@ -44,12 +43,10 @@ import com.android.systemui.plugins.clocks.ClockController
import com.android.systemui.res.R
import com.android.systemui.util.Utils
import kotlin.reflect.KSuspendFunction1
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.launch

/** Binder for the small clock view, large clock view. */
object KeyguardPreviewClockViewBinder {

    @JvmStatic
    fun bind(
        largeClockHostView: View,
@@ -72,51 +69,37 @@ object KeyguardPreviewClockViewBinder {
    @JvmStatic
    fun bind(
        context: Context,
        displayId: Int,
        rootView: ConstraintLayout,
        viewModel: KeyguardPreviewClockViewModel,
        clockEventController: ClockEventController,
        updateClockAppearance: KSuspendFunction1<ClockController, Unit>,
    ) {
        // TODO(b/327668072): When this function is called multiple times, the clock view can be
        //                    gone due to a race condition on removeView and addView.
        rootView.repeatWhenAttached {
            repeatOnLifecycle(Lifecycle.State.STARTED) {
                launch {
                    combine(viewModel.selectedClockSize, viewModel.previewClockPair) { _, clock ->
                            clock
                        }
                        .collect { previewClockPair ->
                            viewModel.lastClockPair?.let { clockPair ->
                                (clockPair.first.largeClock.layout.views +
                                        clockPair.first.smallClock.layout.views)
                                    .forEach { rootView.removeView(it) }
                                (clockPair.second.largeClock.layout.views +
                                        clockPair.second.smallClock.layout.views)
                    var lastClock: ClockController? = null
                    viewModel.previewClock.collect { currentClock ->
                        lastClock?.let { clock ->
                            (clock.largeClock.layout.views + clock.smallClock.layout.views)
                                .forEach { rootView.removeView(it) }
                        }
                            viewModel.lastClockPair = previewClockPair
                            val clockPreview =
                                if (displayId == 0) previewClockPair.first
                                else previewClockPair.second
                            clockEventController.clock = clockPreview
                            updateClockAppearance(clockPreview)
                        lastClock = currentClock
                        updateClockAppearance(currentClock)

                        if (viewModel.shouldHighlightSelectedAffordance) {
                                (clockPreview.largeClock.layout.views +
                                        clockPreview.smallClock.layout.views)
                            (currentClock.largeClock.layout.views +
                                    currentClock.smallClock.layout.views)
                                .forEach { it.alpha = KeyguardPreviewRenderer.DIM_ALPHA }
                        }
                            clockPreview.largeClock.layout.views.forEach {
                        currentClock.largeClock.layout.views.forEach {
                            (it.parent as? ViewGroup)?.removeView(it)
                            rootView.addView(it)
                        }

                            clockPreview.smallClock.layout.views.forEach {
                        currentClock.smallClock.layout.views.forEach {
                            (it.parent as? ViewGroup)?.removeView(it)
                            rootView.addView(it)
                        }
                            applyPreviewConstraints(context, rootView, viewModel)
                        applyPreviewConstraints(context, rootView, currentClock, viewModel)
                    }
                }
            }
@@ -170,15 +153,13 @@ object KeyguardPreviewClockViewBinder {
    private fun applyPreviewConstraints(
        context: Context,
        rootView: ConstraintLayout,
        previewClock: ClockController,
        viewModel: KeyguardPreviewClockViewModel
    ) {
        val cs = ConstraintSet().apply { clone(rootView) }
        val clockPair = viewModel.previewClockPair.value
        applyClockDefaultConstraints(context, cs)
        clockPair.first.largeClock.layout.applyPreviewConstraints(cs)
        clockPair.first.smallClock.layout.applyPreviewConstraints(cs)
        clockPair.second.largeClock.layout.applyPreviewConstraints(cs)
        clockPair.second.smallClock.layout.applyPreviewConstraints(cs)
        previewClock.largeClock.layout.applyPreviewConstraints(cs)
        previewClock.smallClock.layout.applyPreviewConstraints(cs)

        // When selectedClockSize is the initial value, make both clocks invisible to avoid
        // flickering
@@ -194,12 +175,9 @@ object KeyguardPreviewClockViewBinder {
                SettingsClockSize.SMALL -> VISIBLE
                null -> INVISIBLE
            }

        cs.apply {
            setVisibility(clockPair.first.largeClock.layout.views, largeClockVisibility)
            setVisibility(clockPair.first.smallClock.layout.views, smallClockVisibility)
            setVisibility(clockPair.second.largeClock.layout.views, largeClockVisibility)
            setVisibility(clockPair.second.smallClock.layout.views, smallClockVisibility)
            setVisibility(previewClock.largeClock.layout.views, largeClockVisibility)
            setVisibility(previewClock.smallClock.layout.views, smallClockVisibility)
        }
        cs.applyTo(rootView)
    }
+0 −2
Original line number Diff line number Diff line
@@ -408,10 +408,8 @@ constructor(
            if (migrateClocksToBlueprint()) {
                KeyguardPreviewClockViewBinder.bind(
                    context,
                    displayId,
                    keyguardRootView,
                    clockViewModel,
                    clockController,
                    ::updateClockAppearance
                )
            } else {
+2 −12
Original line number Diff line number Diff line
@@ -24,10 +24,8 @@ import com.android.systemui.plugins.clocks.ClockController
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn

/** View model for the small clock view, large clock view. */
class KeyguardPreviewClockViewModel
@@ -45,15 +43,7 @@ constructor(
    val isSmallClockVisible: Flow<Boolean> =
        interactor.selectedClockSize.map { it == SettingsClockSize.SMALL }

    var lastClockPair: Pair<ClockController, ClockController>? = null
    val previewClock: Flow<ClockController> = interactor.previewClock

    val previewClockPair: StateFlow<Pair<ClockController, ClockController>> =
        interactor.previewClockPair

    val selectedClockSize: StateFlow<SettingsClockSize?> =
        interactor.selectedClockSize.stateIn(
            scope = applicationScope,
            started = SharingStarted.WhileSubscribed(),
            initialValue = null
        )
    val selectedClockSize: StateFlow<SettingsClockSize?> = interactor.selectedClockSize
}
Loading