Loading packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSlider.kt +11 −6 Original line number Diff line number Diff line Loading @@ -192,7 +192,11 @@ fun VolumeSlider( hapticsViewModelFactory?.let { Haptics.Enabled( hapticsViewModelFactory = it, hapticFilter = state.hapticFilter, hapticConfigs = VolumeHapticsConfigsProvider.discreteConfigs( state.valueRange.stepSize(), state.hapticFilter, ), orientation = Orientation.Horizontal, ) } ?: Haptics.Disabled, Loading Loading @@ -372,16 +376,15 @@ private fun setUpHapticsViewModel( hapticsViewModelFactory: SliderHapticsViewModel.Factory?, ): SliderHapticsViewModel? { return hapticsViewModelFactory?.let { val configs = VolumeHapticsConfigsProvider.discreteConfigs(valueRange.stepSize(), hapticFilter) rememberViewModel(traceName = "SliderHapticsViewModel") { it.create( interactionSource, valueRange, Orientation.Horizontal, VolumeHapticsConfigsProvider.sliderHapticFeedbackConfig( valueRange, hapticFilter, ), VolumeHapticsConfigsProvider.seekableSliderTrackerConfig, configs.hapticFeedbackConfig, configs.sliderTrackerConfig, ) } .also { hapticsViewModel -> Loading @@ -399,3 +402,5 @@ private fun setUpHapticsViewModel( } } } private fun ClosedFloatingPointRange<Float>.stepSize(): Float = 1f / (endInclusive - start) packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSliderViewBinder.kt +5 −1 Original line number Diff line number Diff line Loading @@ -44,6 +44,7 @@ import com.android.systemui.volume.dialog.sliders.dagger.VolumeDialogSliderScope import com.android.systemui.volume.dialog.sliders.ui.compose.SliderTrack import com.android.systemui.volume.dialog.sliders.ui.viewmodel.VolumeDialogOverscrollViewModel import com.android.systemui.volume.dialog.sliders.ui.viewmodel.VolumeDialogSliderViewModel import com.android.systemui.volume.haptics.ui.VolumeHapticsConfigsProvider import com.android.systemui.volume.ui.compose.slider.AccessibilityParams import com.android.systemui.volume.ui.compose.slider.Haptics import com.android.systemui.volume.ui.compose.slider.Slider Loading Loading @@ -130,7 +131,10 @@ private fun VolumeDialogSlider( hapticsViewModelFactory?.let { Haptics.Enabled( hapticsViewModelFactory = it, hapticFilter = SliderHapticFeedbackFilter(), hapticConfigs = VolumeHapticsConfigsProvider.continuousConfigs( SliderHapticFeedbackFilter() ), orientation = Orientation.Vertical, ) } ?: Haptics.Disabled, Loading packages/SystemUI/src/com/android/systemui/volume/haptics/ui/VolumeHapticsConfigsProvider.kt +50 −18 Original line number Diff line number Diff line Loading @@ -22,23 +22,55 @@ import com.android.systemui.haptics.slider.SliderHapticFeedbackFilter object VolumeHapticsConfigsProvider { fun sliderHapticFeedbackConfig( valueRange: ClosedFloatingPointRange<Float>, filter: SliderHapticFeedbackFilter = SliderHapticFeedbackFilter(), ): SliderHapticFeedbackConfig { val sliderStepSize = 1f / (valueRange.endInclusive - valueRange.start) return SliderHapticFeedbackConfig( fun discreteConfigs(stepSize: Float, filter: SliderHapticFeedbackFilter): VolumeHapticsConfigs = provideConfigs(stepSize, filter) fun continuousConfigs(filter: SliderHapticFeedbackFilter): VolumeHapticsConfigs = provideConfigs(stepSize = 0f, filter) private fun provideConfigs( stepSize: Float, filter: SliderHapticFeedbackFilter, ): VolumeHapticsConfigs { val hapticFeedbackConfig: SliderHapticFeedbackConfig val trackerConfig: SeekableSliderTrackerConfig if (stepSize == 0f) { // Create a set of continuous configs hapticFeedbackConfig = SliderHapticFeedbackConfig( additionalVelocityMaxBump = 0.1f, deltaProgressForDragThreshold = 0.05f, numberOfLowTicks = 4, maxVelocityToScale = 0.5f, /* slider progress(from 0 to 1) per sec */ filter = filter, ) trackerConfig = SeekableSliderTrackerConfig( lowerBookendThreshold = 0.01f, upperBookendThreshold = 0.99f, ) } else { // Create a set of discrete configs hapticFeedbackConfig = SliderHapticFeedbackConfig( lowerBookendScale = 0.2f, progressBasedDragMinScale = 0.2f, progressBasedDragMaxScale = 0.5f, deltaProgressForDragThreshold = 0f, additionalVelocityMaxBump = 0.2f, maxVelocityToScale = 0.1f, /* slider progress(from 0 to 1) per sec */ sliderStepSize = sliderStepSize, sliderStepSize = stepSize, filter = filter, ) } val seekableSliderTrackerConfig = trackerConfig = SeekableSliderTrackerConfig(lowerBookendThreshold = 0f, upperBookendThreshold = 1f) } return VolumeHapticsConfigs(hapticFeedbackConfig, trackerConfig) } } // A collection of configuration parameters for the haptics in the slider data class VolumeHapticsConfigs( val hapticFeedbackConfig: SliderHapticFeedbackConfig, val sliderTrackerConfig: SeekableSliderTrackerConfig, ) packages/SystemUI/src/com/android/systemui/volume/ui/compose/slider/Slider.kt +15 −21 Original line number Diff line number Diff line Loading @@ -36,7 +36,6 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableFloatStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.Modifier import androidx.compose.ui.semantics.ProgressBarRangeInfo import androidx.compose.ui.semantics.SemanticsPropertyReceiver Loading @@ -46,14 +45,10 @@ import androidx.compose.ui.semantics.disabled import androidx.compose.ui.semantics.progressBarRangeInfo import androidx.compose.ui.semantics.setProgress import androidx.compose.ui.semantics.stateDescription import com.android.systemui.haptics.slider.SliderHapticFeedbackFilter import com.android.systemui.haptics.slider.compose.ui.SliderHapticsViewModel import com.android.systemui.lifecycle.rememberViewModel import com.android.systemui.volume.haptics.ui.VolumeHapticsConfigsProvider import com.android.systemui.volume.haptics.ui.VolumeHapticsConfigs import kotlin.math.round import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.map @Composable fun Slider( Loading Loading @@ -95,7 +90,7 @@ fun Slider( val sliderState = remember(valueRange) { SliderState(value = animatedValue, valueRange = valueRange) } val valueChange: (Float) -> Unit = { newValue -> hapticsViewModel?.onValueChange(newValue) hapticsViewModel?.addVelocityDataPoint(newValue) onValueChanged(newValue) } val semantics = Loading Loading @@ -193,23 +188,22 @@ private fun Haptics.createViewModel( interactionSource, valueRange, orientation, VolumeHapticsConfigsProvider.sliderHapticFeedbackConfig( valueRange, hapticFilter, ), VolumeHapticsConfigsProvider.seekableSliderTrackerConfig, hapticConfigs.hapticFeedbackConfig, hapticConfigs.sliderTrackerConfig, ) } .also { hapticsViewModel -> var lastDiscreteStep by remember { mutableFloatStateOf(value) } var lastValue by remember { mutableFloatStateOf(value) } LaunchedEffect(value) { snapshotFlow { value } .map { round(it) } .filter { it != lastDiscreteStep } .distinctUntilChanged() .collect { discreteStep -> lastDiscreteStep = discreteStep hapticsViewModel.onValueChange(discreteStep) val roundedValue = if (hapticConfigs.hapticFeedbackConfig.sliderStepSize != 0f) { round(value) } else { value } if (roundedValue != lastValue) { lastValue = roundedValue hapticsViewModel.onValueChange(roundedValue) } } } Loading @@ -228,7 +222,7 @@ sealed interface Haptics { data class Enabled( val hapticsViewModelFactory: SliderHapticsViewModel.Factory, val hapticFilter: SliderHapticFeedbackFilter, val hapticConfigs: VolumeHapticsConfigs, val orientation: Orientation, ) : Haptics } Loading
packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSlider.kt +11 −6 Original line number Diff line number Diff line Loading @@ -192,7 +192,11 @@ fun VolumeSlider( hapticsViewModelFactory?.let { Haptics.Enabled( hapticsViewModelFactory = it, hapticFilter = state.hapticFilter, hapticConfigs = VolumeHapticsConfigsProvider.discreteConfigs( state.valueRange.stepSize(), state.hapticFilter, ), orientation = Orientation.Horizontal, ) } ?: Haptics.Disabled, Loading Loading @@ -372,16 +376,15 @@ private fun setUpHapticsViewModel( hapticsViewModelFactory: SliderHapticsViewModel.Factory?, ): SliderHapticsViewModel? { return hapticsViewModelFactory?.let { val configs = VolumeHapticsConfigsProvider.discreteConfigs(valueRange.stepSize(), hapticFilter) rememberViewModel(traceName = "SliderHapticsViewModel") { it.create( interactionSource, valueRange, Orientation.Horizontal, VolumeHapticsConfigsProvider.sliderHapticFeedbackConfig( valueRange, hapticFilter, ), VolumeHapticsConfigsProvider.seekableSliderTrackerConfig, configs.hapticFeedbackConfig, configs.sliderTrackerConfig, ) } .also { hapticsViewModel -> Loading @@ -399,3 +402,5 @@ private fun setUpHapticsViewModel( } } } private fun ClosedFloatingPointRange<Float>.stepSize(): Float = 1f / (endInclusive - start)
packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSliderViewBinder.kt +5 −1 Original line number Diff line number Diff line Loading @@ -44,6 +44,7 @@ import com.android.systemui.volume.dialog.sliders.dagger.VolumeDialogSliderScope import com.android.systemui.volume.dialog.sliders.ui.compose.SliderTrack import com.android.systemui.volume.dialog.sliders.ui.viewmodel.VolumeDialogOverscrollViewModel import com.android.systemui.volume.dialog.sliders.ui.viewmodel.VolumeDialogSliderViewModel import com.android.systemui.volume.haptics.ui.VolumeHapticsConfigsProvider import com.android.systemui.volume.ui.compose.slider.AccessibilityParams import com.android.systemui.volume.ui.compose.slider.Haptics import com.android.systemui.volume.ui.compose.slider.Slider Loading Loading @@ -130,7 +131,10 @@ private fun VolumeDialogSlider( hapticsViewModelFactory?.let { Haptics.Enabled( hapticsViewModelFactory = it, hapticFilter = SliderHapticFeedbackFilter(), hapticConfigs = VolumeHapticsConfigsProvider.continuousConfigs( SliderHapticFeedbackFilter() ), orientation = Orientation.Vertical, ) } ?: Haptics.Disabled, Loading
packages/SystemUI/src/com/android/systemui/volume/haptics/ui/VolumeHapticsConfigsProvider.kt +50 −18 Original line number Diff line number Diff line Loading @@ -22,23 +22,55 @@ import com.android.systemui.haptics.slider.SliderHapticFeedbackFilter object VolumeHapticsConfigsProvider { fun sliderHapticFeedbackConfig( valueRange: ClosedFloatingPointRange<Float>, filter: SliderHapticFeedbackFilter = SliderHapticFeedbackFilter(), ): SliderHapticFeedbackConfig { val sliderStepSize = 1f / (valueRange.endInclusive - valueRange.start) return SliderHapticFeedbackConfig( fun discreteConfigs(stepSize: Float, filter: SliderHapticFeedbackFilter): VolumeHapticsConfigs = provideConfigs(stepSize, filter) fun continuousConfigs(filter: SliderHapticFeedbackFilter): VolumeHapticsConfigs = provideConfigs(stepSize = 0f, filter) private fun provideConfigs( stepSize: Float, filter: SliderHapticFeedbackFilter, ): VolumeHapticsConfigs { val hapticFeedbackConfig: SliderHapticFeedbackConfig val trackerConfig: SeekableSliderTrackerConfig if (stepSize == 0f) { // Create a set of continuous configs hapticFeedbackConfig = SliderHapticFeedbackConfig( additionalVelocityMaxBump = 0.1f, deltaProgressForDragThreshold = 0.05f, numberOfLowTicks = 4, maxVelocityToScale = 0.5f, /* slider progress(from 0 to 1) per sec */ filter = filter, ) trackerConfig = SeekableSliderTrackerConfig( lowerBookendThreshold = 0.01f, upperBookendThreshold = 0.99f, ) } else { // Create a set of discrete configs hapticFeedbackConfig = SliderHapticFeedbackConfig( lowerBookendScale = 0.2f, progressBasedDragMinScale = 0.2f, progressBasedDragMaxScale = 0.5f, deltaProgressForDragThreshold = 0f, additionalVelocityMaxBump = 0.2f, maxVelocityToScale = 0.1f, /* slider progress(from 0 to 1) per sec */ sliderStepSize = sliderStepSize, sliderStepSize = stepSize, filter = filter, ) } val seekableSliderTrackerConfig = trackerConfig = SeekableSliderTrackerConfig(lowerBookendThreshold = 0f, upperBookendThreshold = 1f) } return VolumeHapticsConfigs(hapticFeedbackConfig, trackerConfig) } } // A collection of configuration parameters for the haptics in the slider data class VolumeHapticsConfigs( val hapticFeedbackConfig: SliderHapticFeedbackConfig, val sliderTrackerConfig: SeekableSliderTrackerConfig, )
packages/SystemUI/src/com/android/systemui/volume/ui/compose/slider/Slider.kt +15 −21 Original line number Diff line number Diff line Loading @@ -36,7 +36,6 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableFloatStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.Modifier import androidx.compose.ui.semantics.ProgressBarRangeInfo import androidx.compose.ui.semantics.SemanticsPropertyReceiver Loading @@ -46,14 +45,10 @@ import androidx.compose.ui.semantics.disabled import androidx.compose.ui.semantics.progressBarRangeInfo import androidx.compose.ui.semantics.setProgress import androidx.compose.ui.semantics.stateDescription import com.android.systemui.haptics.slider.SliderHapticFeedbackFilter import com.android.systemui.haptics.slider.compose.ui.SliderHapticsViewModel import com.android.systemui.lifecycle.rememberViewModel import com.android.systemui.volume.haptics.ui.VolumeHapticsConfigsProvider import com.android.systemui.volume.haptics.ui.VolumeHapticsConfigs import kotlin.math.round import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.map @Composable fun Slider( Loading Loading @@ -95,7 +90,7 @@ fun Slider( val sliderState = remember(valueRange) { SliderState(value = animatedValue, valueRange = valueRange) } val valueChange: (Float) -> Unit = { newValue -> hapticsViewModel?.onValueChange(newValue) hapticsViewModel?.addVelocityDataPoint(newValue) onValueChanged(newValue) } val semantics = Loading Loading @@ -193,23 +188,22 @@ private fun Haptics.createViewModel( interactionSource, valueRange, orientation, VolumeHapticsConfigsProvider.sliderHapticFeedbackConfig( valueRange, hapticFilter, ), VolumeHapticsConfigsProvider.seekableSliderTrackerConfig, hapticConfigs.hapticFeedbackConfig, hapticConfigs.sliderTrackerConfig, ) } .also { hapticsViewModel -> var lastDiscreteStep by remember { mutableFloatStateOf(value) } var lastValue by remember { mutableFloatStateOf(value) } LaunchedEffect(value) { snapshotFlow { value } .map { round(it) } .filter { it != lastDiscreteStep } .distinctUntilChanged() .collect { discreteStep -> lastDiscreteStep = discreteStep hapticsViewModel.onValueChange(discreteStep) val roundedValue = if (hapticConfigs.hapticFeedbackConfig.sliderStepSize != 0f) { round(value) } else { value } if (roundedValue != lastValue) { lastValue = roundedValue hapticsViewModel.onValueChange(roundedValue) } } } Loading @@ -228,7 +222,7 @@ sealed interface Haptics { data class Enabled( val hapticsViewModelFactory: SliderHapticsViewModel.Factory, val hapticFilter: SliderHapticFeedbackFilter, val hapticConfigs: VolumeHapticsConfigs, val orientation: Orientation, ) : Haptics }