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

Commit 71cc7888 authored by Juan Sebastian Martinez's avatar Juan Sebastian Martinez
Browse files

Adding haptics to Brightness slider in Compose.

This change integrates the SliderHapticsViewModel into the
BrightnessSlider composable, bring it up to par with the current state
of haptics in this control.

Test: manual. Verified haptics are working correctly while dragging.
Test: presubmit.
Flag: com.android.systemui.haptics_for_compose_sliders
Bug: 341968766
Change-Id: Iac93ecfbb0ec62243563f30da2f8058ea2969b64
parent e7883a44
Loading
Loading
Loading
Loading
+6 −4
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ import com.android.systemui.common.shared.model.ContentDescription
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.common.shared.model.Text
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.haptics.slider.sliderHapticsViewModelFactory
import com.android.systemui.kosmos.applicationCoroutineScope
import com.android.systemui.kosmos.testScope
import com.android.systemui.res.R
@@ -54,6 +55,7 @@ class BrightnessSliderViewModelTest : SysuiTestCase() {
                screenBrightnessInteractor,
                brightnessPolicyEnforcementInteractor,
                applicationCoroutineScope,
                sliderHapticsViewModelFactory,
            )
        }

@@ -61,7 +63,7 @@ class BrightnessSliderViewModelTest : SysuiTestCase() {
    fun setUp() {
        kosmos.fakeScreenBrightnessRepository.setMinMaxBrightness(
            LinearBrightness(minBrightness),
            LinearBrightness(maxBrightness)
            LinearBrightness(maxBrightness),
        )
    }

@@ -79,7 +81,7 @@ class BrightnessSliderViewModelTest : SysuiTestCase() {
                        BrightnessUtils.convertLinearToGammaFloat(
                            brightness,
                            minBrightness,
                            maxBrightness
                            maxBrightness,
                        )
                    )

@@ -91,7 +93,7 @@ class BrightnessSliderViewModelTest : SysuiTestCase() {
                        BrightnessUtils.convertLinearToGammaFloat(
                            brightness,
                            minBrightness,
                            maxBrightness
                            maxBrightness,
                        )
                    )
            }
@@ -122,7 +124,7 @@ class BrightnessSliderViewModelTest : SysuiTestCase() {
                    BrightnessUtils.convertGammaToLinearFloat(
                        newBrightness,
                        minBrightness,
                        maxBrightness
                        maxBrightness,
                    )
                val drag = Drag.Dragging(GammaBrightness(newBrightness))

+31 −7
Original line number Diff line number Diff line
@@ -18,6 +18,8 @@ package com.android.systemui.brightness.ui.compose

import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.foundation.clickable
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.size
import androidx.compose.material3.MaterialTheme
@@ -33,12 +35,17 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.compose.PlatformSlider
import com.android.systemui.Flags
import com.android.systemui.brightness.shared.model.GammaBrightness
import com.android.systemui.brightness.ui.viewmodel.BrightnessSliderViewModel
import com.android.systemui.brightness.ui.viewmodel.Drag
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.common.shared.model.Text
import com.android.systemui.common.ui.compose.Icon
import com.android.systemui.haptics.slider.SeekableSliderTrackerConfig
import com.android.systemui.haptics.slider.SliderHapticFeedbackConfig
import com.android.systemui.haptics.slider.compose.ui.SliderHapticsViewModel
import com.android.systemui.lifecycle.rememberViewModel
import com.android.systemui.utils.PolicyRestriction
import kotlinx.coroutines.launch

@@ -54,12 +61,30 @@ private fun BrightnessSlider(
    onStop: (Int) -> Unit,
    modifier: Modifier = Modifier,
    formatter: (Int) -> String = { "$it" },
    hapticsViewModelFactory: SliderHapticsViewModel.Factory,
) {
    var value by remember(gammaValue) { mutableIntStateOf(gammaValue) }
    val animatedValue by
        animateFloatAsState(targetValue = value.toFloat(), label = "BrightnessSliderAnimatedValue")
    val floatValueRange = valueRange.first.toFloat()..valueRange.last.toFloat()
    val isRestricted = remember(restriction) { restriction is PolicyRestriction.Restricted }
    val interactionSource = remember { MutableInteractionSource() }
    val hapticsViewModel: SliderHapticsViewModel? =
        if (Flags.hapticsForComposeSliders()) {
            rememberViewModel(traceName = "SliderHapticsViewModel") {
                hapticsViewModelFactory.create(
                    interactionSource,
                    floatValueRange,
                    Orientation.Horizontal,
                    SliderHapticFeedbackConfig(
                        maxVelocityToScale = 1f /* slider progress(from 0 to 1) per sec */
                    ),
                    SeekableSliderTrackerConfig(),
                )
            }
        } else {
            null
        }

    PlatformSlider(
        value = animatedValue,
@@ -67,19 +92,19 @@ private fun BrightnessSlider(
        enabled = !isRestricted,
        onValueChange = {
            if (!isRestricted) {
                hapticsViewModel?.onValueChange(it)
                value = it.toInt()
                onDrag(value)
            }
        },
        onValueChangeFinished = {
            if (!isRestricted) {
                hapticsViewModel?.onValueChangeEnded()
                onStop(value)
            }
        },
        modifier =
            modifier.clickable(
                enabled = isRestricted,
            ) {
            modifier.clickable(enabled = isRestricted) {
                if (restriction is PolicyRestriction.Restricted) {
                    onRestrictedClick(restriction)
                }
@@ -98,14 +123,12 @@ private fun BrightnessSlider(
                maxLines = 1,
            )
        },
        interactionSource = interactionSource,
    )
}

@Composable
fun BrightnessSliderContainer(
    viewModel: BrightnessSliderViewModel,
    modifier: Modifier = Modifier,
) {
fun BrightnessSliderContainer(viewModel: BrightnessSliderViewModel, modifier: Modifier = Modifier) {
    val state by viewModel.currentBrightness.collectAsStateWithLifecycle()
    val gamma = state.value
    val coroutineScope = rememberCoroutineScope()
@@ -125,5 +148,6 @@ fun BrightnessSliderContainer(
        onStop = { coroutineScope.launch { viewModel.onDrag(Drag.Stopped(GammaBrightness(it))) } },
        modifier = modifier.fillMaxWidth(),
        formatter = viewModel::formatValue,
        hapticsViewModelFactory = viewModel.hapticsViewModelFactory,
    )
}
+5 −1
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import com.android.systemui.common.shared.model.Icon
import com.android.systemui.common.shared.model.Text
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.haptics.slider.compose.ui.SliderHapticsViewModel
import com.android.systemui.res.R
import com.android.systemui.utils.PolicyRestriction
import javax.inject.Inject
@@ -38,12 +39,13 @@ constructor(
    private val screenBrightnessInteractor: ScreenBrightnessInteractor,
    private val brightnessPolicyEnforcementInteractor: BrightnessPolicyEnforcementInteractor,
    @Application private val applicationScope: CoroutineScope,
    val hapticsViewModelFactory: SliderHapticsViewModel.Factory,
) {
    val currentBrightness =
        screenBrightnessInteractor.gammaBrightness.stateIn(
            applicationScope,
            SharingStarted.WhileSubscribed(),
            GammaBrightness(0)
            GammaBrightness(0),
        )

    val maxBrightness = screenBrightnessInteractor.maxGammaBrightness
@@ -85,6 +87,8 @@ constructor(
/** Represents a drag event in a brightness slider. */
sealed interface Drag {
    val brightness: GammaBrightness

    @JvmInline value class Dragging(override val brightness: GammaBrightness) : Drag

    @JvmInline value class Stopped(override val brightness: GammaBrightness) : Drag
}
+2 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.systemui.brightness.ui.viewmodel

import com.android.systemui.brightness.domain.interactor.brightnessPolicyEnforcementInteractor
import com.android.systemui.brightness.domain.interactor.screenBrightnessInteractor
import com.android.systemui.haptics.slider.sliderHapticsViewModelFactory
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.applicationCoroutineScope

@@ -27,5 +28,6 @@ val Kosmos.brightnessSliderViewModel: BrightnessSliderViewModel by
            screenBrightnessInteractor = screenBrightnessInteractor,
            brightnessPolicyEnforcementInteractor = brightnessPolicyEnforcementInteractor,
            applicationScope = applicationCoroutineScope,
            hapticsViewModelFactory = sliderHapticsViewModelFactory,
        )
    }