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

Commit 9c65f420 authored by Catherine Liang's avatar Catherine Liang
Browse files

Set timeout for color apply

In some cases, system color fails update after the user hits apply, but
the app continues to wait for the color configuraiton change. Therefore
the loading spinner continues to show in the apply button and disables
the user from applying any other changes. Set a reasonable timeout to
end loading.

Flag: com.android.systemui.shared.new_customization_picker_ui
Bug: 426471576
Test: manually verified in and out of SUW, added unit tests
Change-Id: Ibe31138682de24972f50d23125cdd6905c46e63a
parent 094f2648
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -31,6 +31,6 @@ interface ColorPickerRepository2 {
    /** The system selected color option from the generated list of color options */
    val selectedColorOption: Flow<ColorOption?>

    /** Selects a color option with optimistic update */
    suspend fun select(colorOption: ColorOption)
    /** Selects a color option and returns whether the operation was successful */
    suspend fun select(colorOption: ColorOption): Boolean
}
+4 −6
Original line number Diff line number Diff line
@@ -142,20 +142,18 @@ constructor(
            }
            .shareIn(scope = scope, started = SharingStarted.WhileSubscribed(), replay = 1)

    override suspend fun select(colorOption: ColorOption) {
        suspendCancellableCoroutine { continuation ->
    override suspend fun select(colorOption: ColorOption): Boolean {
        return suspendCancellableCoroutine { continuation ->
            colorManager.apply(
                colorOption,
                object : CustomizationManager.Callback {
                    override fun onSuccess() {
                        continuation.resumeWith(Result.success(Unit))
                        continuation.resumeWith(Result.success(true))
                    }

                    override fun onError(throwable: Throwable?) {
                        Log.w(TAG, "Apply theme with error", throwable)
                        continuation.resumeWith(
                            Result.failure(throwable ?: Throwable("Error loading theme bundles"))
                        )
                        continuation.resumeWith(Result.success(false))
                    }
                },
            )
+1 −3
Original line number Diff line number Diff line
@@ -29,7 +29,5 @@ class ColorPickerInteractor2 @Inject constructor(private val repository: ColorPi
    /** List of wallpaper and preset color options on the device, categorized by Color Type */
    val colorOptions = repository.colorOptions

    suspend fun select(colorOption: ColorOption) {
        repository.select(colorOption)
    }
    suspend fun select(colorOption: ColorOption): Boolean = repository.select(colorOption)
}
+29 −9
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.wallpaper.customization.ui.viewmodel

import android.content.Context
import android.util.Log
import com.android.customization.model.color.ColorOption
import com.android.customization.model.color.ColorOptionImpl
import com.android.customization.module.logging.ThemesUserEventLogger
@@ -35,6 +36,7 @@ import dagger.assisted.AssistedInject
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.android.scopes.ViewModelScoped
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.TimeoutCancellationException
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
@@ -45,6 +47,7 @@ import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.take
import kotlinx.coroutines.launch
import kotlinx.coroutines.withTimeout

/** Models UI state for a color picker experience. */
class ColorPickerViewModel2
@@ -175,11 +178,9 @@ constructor(
                } else {
                    {
                        coroutineScope {
                            launch { interactor.select(it) }
                            // Suspend until first color update
                            colorUpdateViewModel.systemColorsUpdatedNoReplay.take(1).collect {
                                return@collect
                            }
                            launch {
                                val success = interactor.select(it)
                                if (success) {
                                    logger.logThemeColorApplied(
                                        it.sourceForLogging,
                                        it.styleForLogging,
@@ -187,6 +188,20 @@ constructor(
                                    )
                                }
                            }
                            // Suspend until first color update, or time out after 3 seconds
                            try {
                                withTimeout(COLOR_UPDATE_TIMEOUT_MILLIS) {
                                    colorUpdateViewModel.systemColorsUpdatedNoReplay
                                        .take(1)
                                        .collect {
                                            return@collect
                                        }
                                }
                            } catch (e: TimeoutCancellationException) {
                                Log.w(TAG, "Timed out waiting for color update", e)
                            }
                        }
                    }
                }
            }
        }
@@ -209,4 +224,9 @@ constructor(
    interface Factory {
        fun create(viewModelScope: CoroutineScope): ColorPickerViewModel2
    }

    companion object {
        const val TAG = "ColorPickerViewModel2"
        const val COLOR_UPDATE_TIMEOUT_MILLIS = 3000L
    }
}
+7 −2
Original line number Diff line number Diff line
@@ -198,7 +198,12 @@ class FakeColorPickerRepository2 @Inject constructor() : ColorPickerRepository2
        return builder.build()
    }

    override suspend fun select(colorOption: ColorOption) {
    var applySuccess = true

    override suspend fun select(colorOption: ColorOption): Boolean {
        if (applySuccess) {
            _selectedColorOption.value = colorOption
        }
        return applySuccess
    }
}
Loading