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

Commit 065184fb authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Make colorContrast setting dependent on framework value" into main

parents 57c4bc4b 53c5f71a
Loading
Loading
Loading
Loading
+6 −3
Original line number Original line Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.customization.picker.settings.data.repository
package com.android.customization.picker.settings.data.repository


import android.app.UiModeManager
import android.app.UiModeManager
import android.app.UiModeManager.ContrastUtils
import com.android.wallpaper.picker.di.modules.BackgroundDispatcher
import com.android.wallpaper.picker.di.modules.BackgroundDispatcher
import com.android.wallpaper.system.UiModeManagerWrapper
import com.android.wallpaper.system.UiModeManagerWrapper
import java.util.concurrent.Executor
import java.util.concurrent.Executor
@@ -35,16 +36,18 @@ constructor(
    uiModeManager: UiModeManagerWrapper,
    uiModeManager: UiModeManagerWrapper,
    @BackgroundDispatcher bgDispatcher: CoroutineDispatcher,
    @BackgroundDispatcher bgDispatcher: CoroutineDispatcher,
) {
) {
    var contrast: Flow<Float> = callbackFlow {
    var contrast: Flow<Int> = callbackFlow {
        val executor: Executor = bgDispatcher.asExecutor()
        val executor: Executor = bgDispatcher.asExecutor()
        val listener =
        val listener =
            UiModeManager.ContrastChangeListener { contrast ->
            UiModeManager.ContrastChangeListener { contrast ->
                // Emit the new contrast value whenever it changes
                // Emit the new contrast value whenever it changes
                trySend(contrast)
                trySend(ContrastUtils.toContrastLevel(contrast))
            }
            }


        // Emit the current contrast value immediately
        // Emit the current contrast value immediately
        uiModeManager.getContrast()?.let { currentContrast -> trySend(currentContrast) }
        uiModeManager.getContrast()?.let { currentContrast ->
            trySend(ContrastUtils.toContrastLevel(currentContrast))
        }


        uiModeManager.addContrastChangeListener(executor, listener)
        uiModeManager.addContrastChangeListener(executor, listener)


+1 −1
Original line number Original line Diff line number Diff line
@@ -25,5 +25,5 @@ import kotlinx.coroutines.flow.Flow
class ColorContrastSectionInteractor
class ColorContrastSectionInteractor
@Inject
@Inject
constructor(colorContrastSectionRepository: ColorContrastSectionRepository) {
constructor(colorContrastSectionRepository: ColorContrastSectionRepository) {
    val contrast: Flow<Float> = colorContrastSectionRepository.contrast
    val contrast: Flow<Int> = colorContrastSectionRepository.contrast
}
}
+20 −24
Original line number Original line Diff line number Diff line
@@ -16,6 +16,10 @@


package com.android.customization.picker.settings.ui.viewmodel
package com.android.customization.picker.settings.ui.viewmodel


import android.app.UiModeManager.ContrastUtils.CONTRAST_LEVEL_HIGH
import android.app.UiModeManager.ContrastUtils.CONTRAST_LEVEL_MEDIUM
import android.app.UiModeManager.ContrastUtils.CONTRAST_LEVEL_STANDARD
import android.util.Log
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.ViewModelProvider
import com.android.customization.picker.settings.domain.interactor.ColorContrastSectionInteractor
import com.android.customization.picker.settings.domain.interactor.ColorContrastSectionInteractor
@@ -28,62 +32,54 @@ import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.map


class ColorContrastSectionViewModel
class ColorContrastSectionViewModel
private constructor(
private constructor(colorContrastSectionInteractor: ColorContrastSectionInteractor) : ViewModel() {
    colorContrastSectionInteractor: ColorContrastSectionInteractor,
) : ViewModel() {


    val summary: Flow<ColorContrastSectionDataViewModel> =
    val summary: Flow<ColorContrastSectionDataViewModel> =
        colorContrastSectionInteractor.contrast.map { contrastValue ->
        colorContrastSectionInteractor.contrast.map { contrastValue ->
            when (contrastValue) {
            when (contrastValue) {
                ContrastValue.STANDARD.value ->
                CONTRAST_LEVEL_STANDARD ->
                    ColorContrastSectionDataViewModel(
                    ColorContrastSectionDataViewModel(
                        Text.Resource(R.string.color_contrast_default_title),
                        Text.Resource(R.string.color_contrast_default_title),
                        Icon.Resource(
                        Icon.Resource(
                            res = R.drawable.ic_contrast_standard,
                            res = R.drawable.ic_contrast_standard,
                            contentDescription = null,
                            contentDescription = null,
                        ),
                    )
                    )
                    )
                CONTRAST_LEVEL_MEDIUM ->
                ContrastValue.MEDIUM.value ->
                    ColorContrastSectionDataViewModel(
                    ColorContrastSectionDataViewModel(
                        Text.Resource(R.string.color_contrast_medium_title),
                        Text.Resource(R.string.color_contrast_medium_title),
                        Icon.Resource(
                        Icon.Resource(
                            res = R.drawable.ic_contrast_medium,
                            res = R.drawable.ic_contrast_medium,
                            contentDescription = null,
                            contentDescription = null,
                        ),
                    )
                    )
                    )
                CONTRAST_LEVEL_HIGH ->
                ContrastValue.HIGH.value ->
                    ColorContrastSectionDataViewModel(
                    ColorContrastSectionDataViewModel(
                        Text.Resource(R.string.color_contrast_high_title),
                        Text.Resource(R.string.color_contrast_high_title),
                        Icon.Resource(
                        Icon.Resource(res = R.drawable.ic_contrast_high, contentDescription = null),
                            res = R.drawable.ic_contrast_high,
                            contentDescription = null,
                        )
                    )
                    )
                else -> {
                else -> {
                    println("Invalid contrast value: $contrastValue")
                    Log.e(TAG, "Invalid contrast value: $contrastValue")
                    throw IllegalArgumentException("Invalid contrast value")
                    throw IllegalArgumentException("Invalid contrast value: $contrastValue")
                }
                }
            }
            }
        }
        }


    enum class ContrastValue(val value: Float) {
        STANDARD(0f),
        MEDIUM(0.5f),
        HIGH(1f)
    }

    @Singleton
    @Singleton
    class Factory
    class Factory
    @Inject
    @Inject
    constructor(
    constructor(private val colorContrastSectionInteractor: ColorContrastSectionInteractor) :
        private val colorContrastSectionInteractor: ColorContrastSectionInteractor,
        ViewModelProvider.Factory {
    ) : ViewModelProvider.Factory {
        override fun <T : ViewModel> create(modelClass: Class<T>): T {
        override fun <T : ViewModel> create(modelClass: Class<T>): T {
            @Suppress("UNCHECKED_CAST")
            @Suppress("UNCHECKED_CAST")
            return ColorContrastSectionViewModel(
            return ColorContrastSectionViewModel(
                colorContrastSectionInteractor = colorContrastSectionInteractor,
                colorContrastSectionInteractor = colorContrastSectionInteractor
            )
            )
                as T
                as T
        }
        }
    }
    }

    companion object {
        private const val TAG = "ColorContrastSectionViewModel"
    }
}
}
+5 −2
Original line number Original line Diff line number Diff line
@@ -16,6 +16,7 @@


package com.android.customization.model.picker.settings.data.repository
package com.android.customization.model.picker.settings.data.repository


import android.app.UiModeManager.ContrastUtils
import androidx.test.filters.SmallTest
import androidx.test.filters.SmallTest
import com.android.customization.picker.settings.data.repository.ColorContrastSectionRepository
import com.android.customization.picker.settings.data.repository.ColorContrastSectionRepository
import com.android.wallpaper.testing.FakeUiModeManager
import com.android.wallpaper.testing.FakeUiModeManager
@@ -61,8 +62,10 @@ class ColorContrastSectionRepositoryTest {
    fun contrastFlowEmitsValues() =
    fun contrastFlowEmitsValues() =
        testScope.runTest {
        testScope.runTest {
            val nextContrastValues = listOf(0.5f, 0.7f, 0.8f)
            val nextContrastValues = listOf(0.5f, 0.7f, 0.8f)
            val expectedContrastValues =
                nextContrastValues.map { ContrastUtils.toContrastLevel(it) }
            // Set up a flow to collect all contrast values
            // Set up a flow to collect all contrast values
            val flowCollector = mutableListOf<Float>()
            val flowCollector = mutableListOf<Int>()
            // Start collecting values from the flow, using an unconfined dispatcher to start
            // Start collecting values from the flow, using an unconfined dispatcher to start
            // collecting from the flow right away (rather than explicitly calling `runCurrent`)
            // collecting from the flow right away (rather than explicitly calling `runCurrent`)
            // See https://developer.android.com/kotlin/flow/test#continuous-collection
            // See https://developer.android.com/kotlin/flow/test#continuous-collection
@@ -74,6 +77,6 @@ class ColorContrastSectionRepositoryTest {


            // Ignore the first contrast value from constructing the repository
            // Ignore the first contrast value from constructing the repository
            val collectedValues = flowCollector.drop(1)
            val collectedValues = flowCollector.drop(1)
            assertThat(collectedValues).containsExactlyElementsIn(nextContrastValues)
            assertThat(collectedValues).containsExactlyElementsIn(expectedContrastValues)
        }
        }
}
}
+5 −3
Original line number Original line Diff line number Diff line
@@ -16,6 +16,7 @@


package com.android.customization.model.picker.settings.domain.interactor
package com.android.customization.model.picker.settings.domain.interactor


import android.app.UiModeManager.ContrastUtils
import androidx.test.filters.SmallTest
import androidx.test.filters.SmallTest
import com.android.customization.picker.settings.domain.interactor.ColorContrastSectionInteractor
import com.android.customization.picker.settings.domain.interactor.ColorContrastSectionInteractor
import com.android.wallpaper.testing.FakeUiModeManager
import com.android.wallpaper.testing.FakeUiModeManager
@@ -47,11 +48,12 @@ class ColorContrastSectionInteractorTest {


    @Test
    @Test
    fun contrastEmitCorrectValuesFromRepository() = runTest {
    fun contrastEmitCorrectValuesFromRepository() = runTest {
        val expectedContrast = 1.5f
        val contrastVal = 0.5f
        uiModeManager.setContrast(expectedContrast)
        val expectedContrastVal = ContrastUtils.toContrastLevel(contrastVal)
        uiModeManager.setContrast(contrastVal)


        val result = interactor.contrast.first()
        val result = interactor.contrast.first()


        assertThat(result).isEqualTo(expectedContrast)
        assertThat(result).isEqualTo(expectedContrastVal)
    }
    }
}
}
Loading