Loading packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSlider.kt +20 −3 Original line number Diff line number Diff line Loading @@ -67,6 +67,7 @@ import com.android.systemui.Flags import com.android.systemui.common.shared.model.Icon import com.android.systemui.common.ui.compose.Icon import com.android.systemui.compose.modifiers.sysuiResTag 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.res.R Loading Loading @@ -104,7 +105,13 @@ fun VolumeSlider( val value by valueState(state) val interactionSource = remember { MutableInteractionSource() } val hapticsViewModel: SliderHapticsViewModel? = setUpHapticsViewModel(value, state.valueRange, interactionSource, hapticsViewModelFactory) setUpHapticsViewModel( value, state.valueRange, state.hapticFilter, interactionSource, hapticsViewModelFactory, ) Column(modifier = modifier.animateContentSize(), verticalArrangement = Arrangement.Top) { Row( Loading Loading @@ -220,7 +227,13 @@ private fun LegacyVolumeSlider( val value by valueState(state) val interactionSource = remember { MutableInteractionSource() } val hapticsViewModel: SliderHapticsViewModel? = setUpHapticsViewModel(value, state.valueRange, interactionSource, hapticsViewModelFactory) setUpHapticsViewModel( value, state.valueRange, state.hapticFilter, interactionSource, hapticsViewModelFactory, ) PlatformSlider( modifier = Loading Loading @@ -338,6 +351,7 @@ private fun SliderIcon( fun setUpHapticsViewModel( value: Float, valueRange: ClosedFloatingPointRange<Float>, hapticFilter: SliderHapticFeedbackFilter, interactionSource: MutableInteractionSource, hapticsViewModelFactory: SliderHapticsViewModel.Factory?, ): SliderHapticsViewModel? { Loading @@ -347,7 +361,10 @@ fun setUpHapticsViewModel( interactionSource, valueRange, Orientation.Horizontal, VolumeHapticsConfigsProvider.sliderHapticFeedbackConfig(valueRange), VolumeHapticsConfigsProvider.sliderHapticFeedbackConfig( valueRange, hapticFilter, ), VolumeHapticsConfigsProvider.seekableSliderTrackerConfig, ) } Loading packages/SystemUI/src/com/android/systemui/haptics/slider/SliderHapticFeedbackConfig.kt +2 −0 Original line number Diff line number Diff line Loading @@ -49,4 +49,6 @@ data class SliderHapticFeedbackConfig( @FloatRange(from = 0.0, fromInclusive = false) val exponent: Float = 1f / 0.89f, /** The step-size that defines the slider quantization. Zero represents a continuous slider */ @FloatRange(from = 0.0) val sliderStepSize: Float = 0f, /** A filter that determines values for which haptics are triggered */ val filter: SliderHapticFeedbackFilter = SliderHapticFeedbackFilter(), ) packages/SystemUI/src/com/android/systemui/haptics/slider/SliderHapticFeedbackFilter.kt 0 → 100644 +29 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.systemui.haptics.slider /** * This filter is used by the [SliderHapticFeedbackProvider] to filter-out haptics if the slider * state logic needs to avoid certain vibrations. * * @param[vibrateOnUpperBookend] Tell the provider if we should vibrate on the upper bookend. * @param[vibrateOnLowerBookend] Tell the provider if we should vibrate on the lower bookend. */ data class SliderHapticFeedbackFilter( var vibrateOnUpperBookend: Boolean = true, var vibrateOnLowerBookend: Boolean = true, ) packages/SystemUI/src/com/android/systemui/haptics/slider/SliderHapticFeedbackProvider.kt +2 −2 Original line number Diff line number Diff line Loading @@ -218,14 +218,14 @@ class SliderHapticFeedbackProvider( } override fun onLowerBookend() { if (!hasVibratedAtLowerBookend) { if (!hasVibratedAtLowerBookend && config.filter.vibrateOnLowerBookend) { vibrateOnEdgeCollision(abs(velocityProvider.getTrackedVelocity())) hasVibratedAtLowerBookend = true } } override fun onUpperBookend() { if (!hasVibratedAtUpperBookend) { if (!hasVibratedAtUpperBookend && config.filter.vibrateOnUpperBookend) { vibrateOnEdgeCollision(abs(velocityProvider.getTrackedVelocity())) hasVibratedAtUpperBookend = true } Loading packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java +3 −1 Original line number Diff line number Diff line Loading @@ -125,6 +125,7 @@ import com.android.systemui.haptics.slider.HapticSliderPlugin; import com.android.systemui.haptics.slider.HapticSliderViewBinder; import com.android.systemui.haptics.slider.SeekableSliderTrackerConfig; import com.android.systemui.haptics.slider.SliderHapticFeedbackConfig; import com.android.systemui.haptics.slider.SliderHapticFeedbackFilter; import com.android.systemui.media.dialog.MediaOutputDialogManager; import com.android.systemui.plugins.VolumeDialog; import com.android.systemui.plugins.VolumeDialogController; Loading Loading @@ -2698,7 +2699,8 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, /* upperBookendScale= */ 1f, /* lowerBookendScale= */ 0.05f, /* exponent= */ 1f / 0.89f, /* sliderStepSize = */ 0f); /* sliderStepSize = */ 0f, /* filter =*/new SliderHapticFeedbackFilter()); private static final SeekableSliderTrackerConfig sSliderTrackerConfig = new SeekableSliderTrackerConfig( /* waitTimeMillis= */100, Loading Loading
packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSlider.kt +20 −3 Original line number Diff line number Diff line Loading @@ -67,6 +67,7 @@ import com.android.systemui.Flags import com.android.systemui.common.shared.model.Icon import com.android.systemui.common.ui.compose.Icon import com.android.systemui.compose.modifiers.sysuiResTag 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.res.R Loading Loading @@ -104,7 +105,13 @@ fun VolumeSlider( val value by valueState(state) val interactionSource = remember { MutableInteractionSource() } val hapticsViewModel: SliderHapticsViewModel? = setUpHapticsViewModel(value, state.valueRange, interactionSource, hapticsViewModelFactory) setUpHapticsViewModel( value, state.valueRange, state.hapticFilter, interactionSource, hapticsViewModelFactory, ) Column(modifier = modifier.animateContentSize(), verticalArrangement = Arrangement.Top) { Row( Loading Loading @@ -220,7 +227,13 @@ private fun LegacyVolumeSlider( val value by valueState(state) val interactionSource = remember { MutableInteractionSource() } val hapticsViewModel: SliderHapticsViewModel? = setUpHapticsViewModel(value, state.valueRange, interactionSource, hapticsViewModelFactory) setUpHapticsViewModel( value, state.valueRange, state.hapticFilter, interactionSource, hapticsViewModelFactory, ) PlatformSlider( modifier = Loading Loading @@ -338,6 +351,7 @@ private fun SliderIcon( fun setUpHapticsViewModel( value: Float, valueRange: ClosedFloatingPointRange<Float>, hapticFilter: SliderHapticFeedbackFilter, interactionSource: MutableInteractionSource, hapticsViewModelFactory: SliderHapticsViewModel.Factory?, ): SliderHapticsViewModel? { Loading @@ -347,7 +361,10 @@ fun setUpHapticsViewModel( interactionSource, valueRange, Orientation.Horizontal, VolumeHapticsConfigsProvider.sliderHapticFeedbackConfig(valueRange), VolumeHapticsConfigsProvider.sliderHapticFeedbackConfig( valueRange, hapticFilter, ), VolumeHapticsConfigsProvider.seekableSliderTrackerConfig, ) } Loading
packages/SystemUI/src/com/android/systemui/haptics/slider/SliderHapticFeedbackConfig.kt +2 −0 Original line number Diff line number Diff line Loading @@ -49,4 +49,6 @@ data class SliderHapticFeedbackConfig( @FloatRange(from = 0.0, fromInclusive = false) val exponent: Float = 1f / 0.89f, /** The step-size that defines the slider quantization. Zero represents a continuous slider */ @FloatRange(from = 0.0) val sliderStepSize: Float = 0f, /** A filter that determines values for which haptics are triggered */ val filter: SliderHapticFeedbackFilter = SliderHapticFeedbackFilter(), )
packages/SystemUI/src/com/android/systemui/haptics/slider/SliderHapticFeedbackFilter.kt 0 → 100644 +29 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.systemui.haptics.slider /** * This filter is used by the [SliderHapticFeedbackProvider] to filter-out haptics if the slider * state logic needs to avoid certain vibrations. * * @param[vibrateOnUpperBookend] Tell the provider if we should vibrate on the upper bookend. * @param[vibrateOnLowerBookend] Tell the provider if we should vibrate on the lower bookend. */ data class SliderHapticFeedbackFilter( var vibrateOnUpperBookend: Boolean = true, var vibrateOnLowerBookend: Boolean = true, )
packages/SystemUI/src/com/android/systemui/haptics/slider/SliderHapticFeedbackProvider.kt +2 −2 Original line number Diff line number Diff line Loading @@ -218,14 +218,14 @@ class SliderHapticFeedbackProvider( } override fun onLowerBookend() { if (!hasVibratedAtLowerBookend) { if (!hasVibratedAtLowerBookend && config.filter.vibrateOnLowerBookend) { vibrateOnEdgeCollision(abs(velocityProvider.getTrackedVelocity())) hasVibratedAtLowerBookend = true } } override fun onUpperBookend() { if (!hasVibratedAtUpperBookend) { if (!hasVibratedAtUpperBookend && config.filter.vibrateOnUpperBookend) { vibrateOnEdgeCollision(abs(velocityProvider.getTrackedVelocity())) hasVibratedAtUpperBookend = true } Loading
packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java +3 −1 Original line number Diff line number Diff line Loading @@ -125,6 +125,7 @@ import com.android.systemui.haptics.slider.HapticSliderPlugin; import com.android.systemui.haptics.slider.HapticSliderViewBinder; import com.android.systemui.haptics.slider.SeekableSliderTrackerConfig; import com.android.systemui.haptics.slider.SliderHapticFeedbackConfig; import com.android.systemui.haptics.slider.SliderHapticFeedbackFilter; import com.android.systemui.media.dialog.MediaOutputDialogManager; import com.android.systemui.plugins.VolumeDialog; import com.android.systemui.plugins.VolumeDialogController; Loading Loading @@ -2698,7 +2699,8 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, /* upperBookendScale= */ 1f, /* lowerBookendScale= */ 0.05f, /* exponent= */ 1f / 0.89f, /* sliderStepSize = */ 0f); /* sliderStepSize = */ 0f, /* filter =*/new SliderHapticFeedbackFilter()); private static final SeekableSliderTrackerConfig sSliderTrackerConfig = new SeekableSliderTrackerConfig( /* waitTimeMillis= */100, Loading