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

Commit e0e30ec1 authored by Catherine Liang's avatar Catherine Liang
Browse files

Color Picker reset support (1/3)

Add color picker reset support. Refactored WallpaperColorsViewModel as
well to be provided from the WPP2 injector rather than from the
ViewModelProvider. This CL also moves optimistic update from the
repository layer to the interactor layer.

Bug: 267803746
Bug: 269339630
Bug: 269451870
Test: Unit tests, and manual tests including changing wallpaper to verify that
color options are updated, setting system color, setting and resetting
color with a combination of wallpaper and basic colors, resetting after
making changes to both wallpaper and color option

Change-Id: I27f47621e2f187449b1642ed0794c63efef9d37f
parent d4daeff1
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -107,6 +107,9 @@ public abstract class ColorOption implements CustomizationOption<ColorOption> {
        if (other == null) {
            return false;
        }
        if (mStyle != other.getStyle()) {
            return false;
        }
        if (mIsDefault) {
            return other.isDefault() || TextUtils.isEmpty(other.getSerializedPackages())
                    || EMPTY_JSON.equals(other.getSerializedPackages());
+25 −4
Original line number Diff line number Diff line
@@ -47,6 +47,7 @@ import com.android.customization.picker.clock.ui.viewmodel.ClockSectionViewModel
import com.android.customization.picker.clock.ui.viewmodel.ClockSettingsViewModel
import com.android.customization.picker.color.data.repository.ColorPickerRepositoryImpl
import com.android.customization.picker.color.domain.interactor.ColorPickerInteractor
import com.android.customization.picker.color.domain.interactor.ColorPickerSnapshotRestorer
import com.android.customization.picker.color.ui.viewmodel.ColorPickerViewModel
import com.android.customization.picker.notifications.data.repository.NotificationsRepository
import com.android.customization.picker.notifications.domain.interactor.NotificationsInteractor
@@ -100,6 +101,7 @@ open class ThemePickerInjector : WallpaperPicker2Injector(), CustomizationInject
    private var notificationSectionViewModelFactory: NotificationSectionViewModel.Factory? = null
    private var colorPickerInteractor: ColorPickerInteractor? = null
    private var colorPickerViewModelFactory: ColorPickerViewModel.Factory? = null
    private var colorPickerSnapshotRestorer: ColorPickerSnapshotRestorer? = null
    private var darkModeSnapshotRestorer: DarkModeSnapshotRestorer? = null
    private var themedIconSnapshotRestorer: ThemedIconSnapshotRestorer? = null
    private var themedIconInteractor: ThemedIconInteractor? = null
@@ -113,8 +115,7 @@ open class ThemePickerInjector : WallpaperPicker2Injector(), CustomizationInject
            ?: DefaultCustomizationSections(
                    getColorPickerViewModelFactory(
                        context = activity,
                        wallpaperColorsViewModel =
                            ViewModelProvider(activity)[WallpaperColorsViewModel::class.java],
                        wallpaperColorsViewModel = getWallpaperColorsViewModel(),
                    ),
                    getKeyguardQuickAffordancePickerInteractor(activity),
                    getKeyguardQuickAffordancePickerViewModelFactory(activity),
@@ -190,6 +191,8 @@ open class ThemePickerInjector : WallpaperPicker2Injector(), CustomizationInject
            this[KEY_DARK_MODE_SNAPSHOT_RESTORER] = getDarkModeSnapshotRestorer(context)
            this[KEY_THEMED_ICON_SNAPSHOT_RESTORER] = getThemedIconSnapshotRestorer(context)
            this[KEY_APP_GRID_SNAPSHOT_RESTORER] = getGridSnapshotRestorer(context)
            this[KEY_COLOR_PICKER_SNAPSHOT_RESTORER] =
                getColorPickerSnapshotRestorer(context, getWallpaperColorsViewModel())
        }
    }

@@ -346,7 +349,12 @@ open class ThemePickerInjector : WallpaperPicker2Injector(), CustomizationInject
        wallpaperColorsViewModel: WallpaperColorsViewModel,
    ): ColorPickerInteractor {
        return colorPickerInteractor
            ?: ColorPickerInteractor(ColorPickerRepositoryImpl(context, wallpaperColorsViewModel))
            ?: ColorPickerInteractor(
                    repository = ColorPickerRepositoryImpl(context, wallpaperColorsViewModel),
                    snapshotRestorer = {
                        getColorPickerSnapshotRestorer(context, wallpaperColorsViewModel)
                    }
                )
                .also { colorPickerInteractor = it }
    }

@@ -362,6 +370,17 @@ open class ThemePickerInjector : WallpaperPicker2Injector(), CustomizationInject
                .also { colorPickerViewModelFactory = it }
    }

    private fun getColorPickerSnapshotRestorer(
        context: Context,
        wallpaperColorsViewModel: WallpaperColorsViewModel,
    ): ColorPickerSnapshotRestorer {
        return colorPickerSnapshotRestorer
            ?: ColorPickerSnapshotRestorer(
                    getColorPickerInteractor(context, wallpaperColorsViewModel)
                )
                .also { colorPickerSnapshotRestorer = it }
    }

    fun getDarkModeSnapshotRestorer(
        context: Context,
    ): DarkModeSnapshotRestorer {
@@ -460,6 +479,8 @@ open class ThemePickerInjector : WallpaperPicker2Injector(), CustomizationInject
        private val KEY_THEMED_ICON_SNAPSHOT_RESTORER = KEY_DARK_MODE_SNAPSHOT_RESTORER + 1
        @JvmStatic
        private val KEY_APP_GRID_SNAPSHOT_RESTORER = KEY_THEMED_ICON_SNAPSHOT_RESTORER + 1
        @JvmStatic
        private val KEY_COLOR_PICKER_SNAPSHOT_RESTORER = KEY_APP_GRID_SNAPSHOT_RESTORER + 1

        /**
         * When this injector is overridden, this is the minimal value that should be used by
@@ -467,6 +488,6 @@ open class ThemePickerInjector : WallpaperPicker2Injector(), CustomizationInject
         *
         * It should always be greater than the biggest restorer key.
         */
        @JvmStatic protected val MIN_SNAPSHOT_RESTORER_KEY = KEY_APP_GRID_SNAPSHOT_RESTORER + 1
        @JvmStatic protected val MIN_SNAPSHOT_RESTORER_KEY = KEY_COLOR_PICKER_SNAPSHOT_RESTORER + 1
    }
}
+1 −2
Original line number Diff line number Diff line
@@ -25,7 +25,6 @@ import androidx.lifecycle.get
import com.android.customization.module.ThemePickerInjector
import com.android.customization.picker.clock.ui.binder.ClockSettingsBinder
import com.android.wallpaper.R
import com.android.wallpaper.model.WallpaperColorsViewModel
import com.android.wallpaper.module.InjectorProvider
import com.android.wallpaper.picker.AppbarFragment
import com.android.wallpaper.picker.customization.ui.binder.ScreenPreviewBinder
@@ -63,7 +62,7 @@ class ClockSettingsFragment : AppbarFragment() {
        val injector = InjectorProvider.getInjector() as ThemePickerInjector

        val lockScreenView: CardView = view.requireViewById(R.id.lock_preview)
        val colorViewModel = ViewModelProvider(activity)[WallpaperColorsViewModel::class.java]
        val colorViewModel = injector.getWallpaperColorsViewModel()
        val displayUtils = injector.getDisplayUtils(context)
        ScreenPreviewBinder.bind(
                activity = activity,
+4 −6
Original line number Diff line number Diff line
@@ -25,15 +25,13 @@ import kotlinx.coroutines.flow.Flow
 * system color.
 */
interface ColorPickerRepository {
    /**
     * The newly selected color option for overwriting the current active option during an
     * optimistic update, the value is null when no overwriting is needed
     */
    val activeColorOption: Flow<ColorOptionModel?>

    /** List of wallpaper and preset color options on the device, categorized by Color Type */
    val colorOptions: Flow<Map<ColorType, List<ColorOptionModel>>>

    /** Selects a color option with optimistic update */
    fun select(colorOptionModel: ColorOptionModel)
    suspend fun select(colorOptionModel: ColorOptionModel)

    /** Returns the current selected color option based on system settings */
    fun getCurrentColorOption(): ColorOptionModel
}
+43 −34
Original line number Diff line number Diff line
@@ -20,6 +20,8 @@ import android.app.WallpaperColors
import android.content.Context
import android.util.Log
import com.android.customization.model.CustomizationManager
import com.android.customization.model.ResourceConstants.OVERLAY_CATEGORY_COLOR
import com.android.customization.model.ResourceConstants.OVERLAY_CATEGORY_SYSTEM_PALETTE
import com.android.customization.model.color.ColorBundle
import com.android.customization.model.color.ColorCustomizationManager
import com.android.customization.model.color.ColorOption
@@ -27,11 +29,10 @@ import com.android.customization.model.color.ColorSeedOption
import com.android.customization.model.theme.OverlayManagerCompat
import com.android.customization.picker.color.shared.model.ColorOptionModel
import com.android.customization.picker.color.shared.model.ColorType
import com.android.systemui.monet.Style
import com.android.wallpaper.model.WallpaperColorsViewModel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.suspendCancellableCoroutine
@@ -50,17 +51,11 @@ class ColorPickerRepositoryImpl(
    private val colorManager: ColorCustomizationManager =
        ColorCustomizationManager.getInstance(context, OverlayManagerCompat(context))

    private val _activeColorOption = MutableStateFlow<ColorOptionModel?>(null)
    override val activeColorOption: StateFlow<ColorOptionModel?> = _activeColorOption.asStateFlow()

    override val colorOptions: Flow<Map<ColorType, List<ColorOptionModel>>> =
        combine(activeColorOption, homeWallpaperColors, lockWallpaperColors) {
                activeOption,
                homeColors,
                lockColors ->
                Triple(activeOption, homeColors, lockColors)
        combine(homeWallpaperColors, lockWallpaperColors) { homeColors, lockColors ->
                homeColors to lockColors
            }
            .map { (activeOption, homeColors, lockColors) ->
            .map { (homeColors, lockColors) ->
                suspendCancellableCoroutine { continuation ->
                    colorManager.setWallpaperColors(homeColors, lockColors)
                    colorManager.fetchOptions(
@@ -73,9 +68,8 @@ class ColorPickerRepositoryImpl(
                                options?.forEach { option ->
                                    when (option) {
                                        is ColorSeedOption ->
                                            wallpaperColorOptions.add(option.toModel(activeOption))
                                        is ColorBundle ->
                                            presetColorOptions.add(option.toModel(activeOption))
                                            wallpaperColorOptions.add(option.toModel())
                                        is ColorBundle -> presetColorOptions.add(option.toModel())
                                    }
                                }
                                continuation.resumeWith(
@@ -102,33 +96,48 @@ class ColorPickerRepositoryImpl(
                }
            }

    override fun select(colorOptionModel: ColorOptionModel) {
        _activeColorOption.value = colorOptionModel
        val colorOption: ColorOption = colorOptionModel.colorOption
    override suspend fun select(colorOptionModel: ColorOptionModel) =
        suspendCancellableCoroutine { continuation ->
            colorManager.apply(
            colorOption,
                colorOptionModel.colorOption,
                object : CustomizationManager.Callback {
                    override fun onSuccess() {
                    _activeColorOption.value = null
                        continuation.resumeWith(Result.success(Unit))
                    }

                    override fun onError(throwable: Throwable?) {
                    _activeColorOption.value = null
                        Log.w(TAG, "Apply theme with error", throwable)
                        continuation.resumeWith(
                            Result.failure(throwable ?: Throwable("Error loading theme bundles"))
                        )
                    }
                }
            )
        }

    override fun getCurrentColorOption(): ColorOptionModel {
        val overlays = colorManager.currentOverlays
        return ColorOptionModel(
            colorOption =
                // Does not matter whether ColorSeedOption or ColorBundle builder is used here
                // because to apply the color, one just needs a generic ColorOption
                ColorSeedOption.Builder()
                    .addOverlayPackage(
                        OVERLAY_CATEGORY_SYSTEM_PALETTE,
                        overlays[OVERLAY_CATEGORY_SYSTEM_PALETTE]
                    )
                    .addOverlayPackage(OVERLAY_CATEGORY_COLOR, overlays[OVERLAY_CATEGORY_COLOR])
                    .setSource(colorManager.currentColorSource)
                    .setStyle(Style.valueOf(colorManager.currentStyle))
                    .build(),
            isSelected = false,
        )
    }

    private fun ColorOption.toModel(activeColorOption: ColorOptionModel?): ColorOptionModel {
    private fun ColorOption.toModel(): ColorOptionModel {
        return ColorOptionModel(
            colorOption = this,
            isSelected =
                if (activeColorOption != null) {
                    isEquivalent(activeColorOption.colorOption)
                } else {
                    isActive(colorManager)
                },
            isSelected = isActive(colorManager),
        )
    }

Loading