Merge "Inject repeatWhenAttached CoroutineScope to prevent leaking" into main
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/VolumeDialog.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/VolumeDialog.kt
index 5c0cc81..39b434ad 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/VolumeDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/VolumeDialog.kt
@@ -21,20 +21,24 @@
 import android.graphics.PixelFormat
 import android.os.Bundle
 import android.view.MotionEvent
+import android.view.View
 import android.view.ViewGroup
 import android.view.WindowManager
+import com.android.app.tracing.coroutines.coroutineScopeTraced
 import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.lifecycle.repeatWhenAttached
 import com.android.systemui.res.R
 import com.android.systemui.volume.Events
+import com.android.systemui.volume.dialog.dagger.VolumeDialogComponent
 import com.android.systemui.volume.dialog.domain.interactor.VolumeDialogVisibilityInteractor
-import com.android.systemui.volume.dialog.ui.binder.VolumeDialogViewBinder
 import javax.inject.Inject
+import kotlinx.coroutines.awaitCancellation
 
 class VolumeDialog
 @Inject
 constructor(
     @Application context: Context,
-    private val viewBinder: VolumeDialogViewBinder,
+    private val componentFactory: VolumeDialogComponent.Factory,
     private val visibilityInteractor: VolumeDialogVisibilityInteractor,
 ) : Dialog(context, R.style.Theme_SystemUI_Dialog_Volume) {
 
@@ -64,7 +68,14 @@
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
         setContentView(R.layout.volume_dialog)
-        viewBinder.bind(this)
+        requireViewById<View>(R.id.volume_dialog_root).repeatWhenAttached {
+            coroutineScopeTraced("[Volume]dialog") {
+                val component = componentFactory.create(this)
+                with(component.volumeDialogViewBinder()) { bind(this@VolumeDialog) }
+
+                awaitCancellation()
+            }
+        }
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/VolumeDialogPlugin.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/VolumeDialogPlugin.kt
index b912361..094ec39 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/VolumeDialogPlugin.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/VolumeDialogPlugin.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.volume.dialog
 
+import com.android.app.tracing.coroutines.coroutineScopeTraced
 import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.plugins.VolumeDialog
@@ -23,7 +24,6 @@
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Job
-import kotlinx.coroutines.coroutineScope
 
 class VolumeDialogPlugin
 @Inject
@@ -38,7 +38,7 @@
     override fun init(windowType: Int, callback: VolumeDialog.Callback?) {
         job =
             applicationCoroutineScope.launch {
-                coroutineScope {
+                coroutineScopeTraced("[Volume]plugin") {
                     pluginComponent =
                         volumeDialogPluginComponentFactory.create(this).also {
                             it.viewModel().launchVolumeDialog()
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/dagger/VolumeDialogComponent.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/dagger/VolumeDialogComponent.kt
index fb15795..434f6b5 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/dagger/VolumeDialogComponent.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/dagger/VolumeDialogComponent.kt
@@ -20,6 +20,7 @@
 import com.android.systemui.volume.dialog.dagger.scope.VolumeDialog
 import com.android.systemui.volume.dialog.dagger.scope.VolumeDialogScope
 import com.android.systemui.volume.dialog.sliders.dagger.VolumeDialogSliderComponent
+import com.android.systemui.volume.dialog.ui.binder.VolumeDialogViewBinder
 import dagger.BindsInstance
 import dagger.Subcomponent
 import kotlinx.coroutines.CoroutineScope
@@ -32,21 +33,21 @@
 @Subcomponent(modules = [VolumeDialogModule::class])
 interface VolumeDialogComponent {
 
-    /**
-     * Provides a coroutine scope to use inside [VolumeDialogScope].
-     * [com.android.systemui.volume.dialog.VolumeDialogPlugin] manages the lifecycle of this scope.
-     * It's cancelled when the dialog is disposed. This helps to free occupied resources when volume
-     * dialog is not shown.
-     */
-    @VolumeDialog fun coroutineScope(): CoroutineScope
-
-    @VolumeDialogScope fun volumeDialog(): com.android.systemui.volume.dialog.VolumeDialog
+    fun volumeDialogViewBinder(): VolumeDialogViewBinder
 
     fun sliderComponentFactory(): VolumeDialogSliderComponent.Factory
 
     @Subcomponent.Factory
     interface Factory {
 
-        fun create(@BindsInstance @VolumeDialog scope: CoroutineScope): VolumeDialogComponent
+        fun create(
+            /**
+             * Provides a coroutine scope to use inside [VolumeDialogScope].
+             * [com.android.systemui.volume.dialog.VolumeDialogPlugin] manages the lifecycle of this
+             * scope. It's cancelled when the dialog is disposed. This helps to free occupied
+             * resources when volume dialog is not shown.
+             */
+            @BindsInstance @VolumeDialog scope: CoroutineScope
+        ): VolumeDialogComponent
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSliderTouchesViewBinder.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSliderTouchesViewBinder.kt
index 7fd177d..e033624 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSliderTouchesViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSliderTouchesViewBinder.kt
@@ -18,9 +18,6 @@
 
 import android.annotation.SuppressLint
 import android.view.View
-import com.android.systemui.lifecycle.WindowLifecycleState
-import com.android.systemui.lifecycle.repeatWhenAttached
-import com.android.systemui.lifecycle.viewModel
 import com.android.systemui.res.R
 import com.android.systemui.volume.dialog.sliders.dagger.VolumeDialogSliderScope
 import com.android.systemui.volume.dialog.sliders.ui.viewmodel.VolumeDialogSliderTouchesViewModel
@@ -30,22 +27,14 @@
 @VolumeDialogSliderScope
 class VolumeDialogSliderTouchesViewBinder
 @Inject
-constructor(private val viewModelFactory: VolumeDialogSliderTouchesViewModel.Factory) {
+constructor(private val viewModel: VolumeDialogSliderTouchesViewModel) {
 
     @SuppressLint("ClickableViewAccessibility")
     fun bind(view: View) {
         with(view.requireViewById<Slider>(R.id.volume_dialog_slider)) {
-            repeatWhenAttached {
-                viewModel(
-                    traceName = "VolumeDialogSliderTouchesViewBinder",
-                    minWindowLifecycleState = WindowLifecycleState.ATTACHED,
-                    factory = { viewModelFactory.create() },
-                ) { viewModel ->
-                    setOnTouchListener { _, event ->
-                        viewModel.onTouchEvent(event)
-                        false
-                    }
-                }
+            setOnTouchListener { _, event ->
+                viewModel.onTouchEvent(event)
+                false
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSliderViewBinder.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSliderViewBinder.kt
index 1c231b5..f9334df 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSliderViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSliderViewBinder.kt
@@ -20,9 +20,6 @@
 import android.animation.ObjectAnimator
 import android.view.View
 import android.view.animation.DecelerateInterpolator
-import com.android.systemui.lifecycle.WindowLifecycleState
-import com.android.systemui.lifecycle.repeatWhenAttached
-import com.android.systemui.lifecycle.viewModel
 import com.android.systemui.res.R
 import com.android.systemui.volume.dialog.shared.model.VolumeDialogStreamModel
 import com.android.systemui.volume.dialog.sliders.dagger.VolumeDialogSliderScope
@@ -33,7 +30,7 @@
 import com.google.android.material.slider.Slider
 import javax.inject.Inject
 import kotlin.math.roundToInt
-import kotlinx.coroutines.awaitCancellation
+import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.onEach
 
@@ -43,32 +40,20 @@
 class VolumeDialogSliderViewBinder
 @Inject
 constructor(
-    private val viewModelFactory: VolumeDialogSliderViewModel.Factory,
+    private val viewModel: VolumeDialogSliderViewModel,
     private val jankListenerFactory: JankListenerFactory,
 ) {
 
-    fun bind(view: View) {
-        with(view) {
-            val sliderView: Slider =
-                requireViewById<Slider>(R.id.volume_dialog_slider).apply {
-                    labelBehavior = LabelFormatter.LABEL_GONE
-                }
-            repeatWhenAttached {
-                viewModel(
-                    traceName = "VolumeDialogSliderViewBinder",
-                    minWindowLifecycleState = WindowLifecycleState.ATTACHED,
-                    factory = { viewModelFactory.create() },
-                ) { viewModel ->
-                    sliderView.addOnChangeListener { _, value, fromUser ->
-                        viewModel.setStreamVolume(value.roundToInt(), fromUser)
-                    }
-
-                    viewModel.model.onEach { it.bindToSlider(sliderView) }.launchIn(this)
-
-                    awaitCancellation()
-                }
+    fun CoroutineScope.bind(view: View) {
+        val sliderView: Slider =
+            view.requireViewById<Slider>(R.id.volume_dialog_slider).apply {
+                labelBehavior = LabelFormatter.LABEL_GONE
             }
+        sliderView.addOnChangeListener { _, value, fromUser ->
+            viewModel.setStreamVolume(value.roundToInt(), fromUser)
         }
+
+        viewModel.model.onEach { it.bindToSlider(sliderView) }.launchIn(this)
     }
 
     private suspend fun VolumeDialogStreamModel.bindToSlider(slider: Slider) {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSlidersViewBinder.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSlidersViewBinder.kt
index 1b2b4ff..242845a 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSlidersViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSlidersViewBinder.kt
@@ -21,58 +21,47 @@
 import android.view.ViewGroup
 import androidx.annotation.LayoutRes
 import androidx.compose.ui.util.fastForEachIndexed
-import com.android.systemui.lifecycle.WindowLifecycleState
-import com.android.systemui.lifecycle.repeatWhenAttached
-import com.android.systemui.lifecycle.viewModel
 import com.android.systemui.res.R
 import com.android.systemui.volume.dialog.dagger.scope.VolumeDialogScope
 import com.android.systemui.volume.dialog.sliders.dagger.VolumeDialogSliderComponent
 import com.android.systemui.volume.dialog.sliders.ui.viewmodel.VolumeDialogSlidersViewModel
 import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.onEach
 
 @VolumeDialogScope
 class VolumeDialogSlidersViewBinder
 @Inject
-constructor(private val viewModelFactory: VolumeDialogSlidersViewModel.Factory) {
+constructor(private val viewModel: VolumeDialogSlidersViewModel) {
 
-    fun bind(view: View) {
-        with(view) {
-            val floatingSlidersContainer: ViewGroup =
-                requireViewById(R.id.volume_dialog_floating_sliders_container)
-            val mainSliderContainer: View =
-                requireViewById(R.id.volume_dialog_main_slider_container)
-            repeatWhenAttached {
-                viewModel(
-                    traceName = "VolumeDialogSlidersViewBinder",
-                    minWindowLifecycleState = WindowLifecycleState.ATTACHED,
-                    factory = { viewModelFactory.create() },
-                ) { viewModel ->
-                    viewModel.sliders
-                        .onEach { uiModel ->
-                            uiModel.sliderComponent.bindSlider(mainSliderContainer)
+    fun CoroutineScope.bind(view: View) {
+        val floatingSlidersContainer: ViewGroup =
+            view.requireViewById(R.id.volume_dialog_floating_sliders_container)
+        val mainSliderContainer: View =
+            view.requireViewById(R.id.volume_dialog_main_slider_container)
+        viewModel.sliders
+            .onEach { uiModel ->
+                bindSlider(uiModel.sliderComponent, mainSliderContainer)
 
-                            val floatingSliderViewBinders = uiModel.floatingSliderComponent
-                            floatingSlidersContainer.ensureChildCount(
-                                viewLayoutId = R.layout.volume_dialog_slider_floating,
-                                count = floatingSliderViewBinders.size,
-                            )
-                            floatingSliderViewBinders.fastForEachIndexed { index, sliderComponent ->
-                                sliderComponent.bindSlider(
-                                    floatingSlidersContainer.getChildAt(index)
-                                )
-                            }
-                        }
-                        .launchIn(this)
+                val floatingSliderViewBinders = uiModel.floatingSliderComponent
+                floatingSlidersContainer.ensureChildCount(
+                    viewLayoutId = R.layout.volume_dialog_slider_floating,
+                    count = floatingSliderViewBinders.size,
+                )
+                floatingSliderViewBinders.fastForEachIndexed { index, sliderComponent ->
+                    bindSlider(sliderComponent, floatingSlidersContainer.getChildAt(index))
                 }
             }
-        }
+            .launchIn(this)
     }
 
-    private fun VolumeDialogSliderComponent.bindSlider(sliderContainer: View) {
-        sliderViewBinder().bind(sliderContainer)
-        sliderTouchesViewBinder().bind(sliderContainer)
+    private fun CoroutineScope.bindSlider(
+        component: VolumeDialogSliderComponent,
+        sliderContainer: View,
+    ) {
+        with(component.sliderViewBinder()) { bind(sliderContainer) }
+        with(component.sliderTouchesViewBinder()) { bind(sliderContainer) }
     }
 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSliderTouchesViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSliderTouchesViewModel.kt
index 144c75d..9126f45 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSliderTouchesViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSliderTouchesViewModel.kt
@@ -17,20 +17,16 @@
 package com.android.systemui.volume.dialog.sliders.ui.viewmodel
 
 import android.view.MotionEvent
+import com.android.systemui.volume.dialog.sliders.dagger.VolumeDialogSliderScope
 import com.android.systemui.volume.dialog.sliders.domain.interactor.VolumeDialogSliderInputEventsInteractor
-import dagger.assisted.AssistedFactory
-import dagger.assisted.AssistedInject
+import javax.inject.Inject
 
+@VolumeDialogSliderScope
 class VolumeDialogSliderTouchesViewModel
-@AssistedInject
+@Inject
 constructor(private val interactor: VolumeDialogSliderInputEventsInteractor) {
 
     fun onTouchEvent(event: MotionEvent) {
         interactor.onTouchEvent(event)
     }
-
-    @AssistedFactory
-    interface Factory {
-        fun create(): VolumeDialogSliderTouchesViewModel
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSliderViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSliderViewModel.kt
index cf04d45..6dd5b63 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSliderViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSliderViewModel.kt
@@ -21,9 +21,9 @@
 import com.android.systemui.volume.dialog.dagger.scope.VolumeDialog
 import com.android.systemui.volume.dialog.domain.interactor.VolumeDialogVisibilityInteractor
 import com.android.systemui.volume.dialog.shared.model.VolumeDialogStreamModel
+import com.android.systemui.volume.dialog.sliders.dagger.VolumeDialogSliderScope
 import com.android.systemui.volume.dialog.sliders.domain.interactor.VolumeDialogSliderInteractor
-import dagger.assisted.AssistedFactory
-import dagger.assisted.AssistedInject
+import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.Flow
@@ -49,8 +49,9 @@
 private const val VOLUME_UPDATE_GRACE_PERIOD = 1000
 
 @OptIn(ExperimentalCoroutinesApi::class)
+@VolumeDialogSliderScope
 class VolumeDialogSliderViewModel
-@AssistedInject
+@Inject
 constructor(
     private val interactor: VolumeDialogSliderInteractor,
     private val visibilityInteractor: VolumeDialogVisibilityInteractor,
@@ -90,10 +91,4 @@
     private fun getTimestampMillis(): Long = systemClock.uptimeMillis()
 
     private data class VolumeUpdate(val newVolumeLevel: Int, val timestampMillis: Long)
-
-    @AssistedFactory
-    interface Factory {
-
-        fun create(): VolumeDialogSliderViewModel
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSlidersViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSlidersViewModel.kt
index d197223..d8e6aec 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSlidersViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSlidersViewModel.kt
@@ -17,10 +17,10 @@
 package com.android.systemui.volume.dialog.sliders.ui.viewmodel
 
 import com.android.systemui.volume.dialog.dagger.scope.VolumeDialog
+import com.android.systemui.volume.dialog.dagger.scope.VolumeDialogScope
 import com.android.systemui.volume.dialog.sliders.dagger.VolumeDialogSliderComponent
 import com.android.systemui.volume.dialog.sliders.domain.interactor.VolumeDialogSlidersInteractor
-import dagger.assisted.AssistedFactory
-import dagger.assisted.AssistedInject
+import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.SharingStarted
@@ -28,8 +28,9 @@
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.stateIn
 
+@VolumeDialogScope
 class VolumeDialogSlidersViewModel
-@AssistedInject
+@Inject
 constructor(
     @VolumeDialog coroutineScope: CoroutineScope,
     private val slidersInteractor: VolumeDialogSlidersInteractor,
@@ -47,12 +48,6 @@
             }
             .stateIn(coroutineScope, SharingStarted.Eagerly, null)
             .filterNotNull()
-
-    @AssistedFactory
-    interface Factory {
-
-        fun create(): VolumeDialogSlidersViewModel
-    }
 }
 
 /** Models slider ui */
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/binder/VolumeDialogViewBinder.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/binder/VolumeDialogViewBinder.kt
index f6c1743..a3166a9 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/binder/VolumeDialogViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/binder/VolumeDialogViewBinder.kt
@@ -25,9 +25,6 @@
 import android.view.ViewTreeObserver.InternalInsetsInfo
 import androidx.constraintlayout.motion.widget.MotionLayout
 import com.android.internal.view.RotationPolicy
-import com.android.systemui.lifecycle.WindowLifecycleState
-import com.android.systemui.lifecycle.repeatWhenAttached
-import com.android.systemui.lifecycle.viewModel
 import com.android.systemui.res.R
 import com.android.systemui.util.children
 import com.android.systemui.volume.SystemUIInterpolators
@@ -44,7 +41,6 @@
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.awaitCancellation
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.first
 import kotlinx.coroutines.flow.launchIn
@@ -61,7 +57,7 @@
 @Inject
 constructor(
     private val volumeResources: VolumeDialogResources,
-    private val dialogViewModelFactory: VolumeDialogViewModel.Factory,
+    private val viewModel: VolumeDialogViewModel,
     private val jankListenerFactory: JankListenerFactory,
     private val tracer: VolumeTracer,
     private val volumeDialogRingerViewBinder: VolumeDialogRingerViewBinder,
@@ -69,35 +65,27 @@
     private val settingsButtonViewBinder: VolumeDialogSettingsButtonViewBinder,
 ) {
 
-    fun bind(dialog: Dialog) {
+    fun CoroutineScope.bind(dialog: Dialog) {
         // Root view of the Volume Dialog.
         val root: MotionLayout = dialog.requireViewById(R.id.volume_dialog_root)
         root.alpha = 0f
-        root.repeatWhenAttached {
-            root.viewModel(
-                traceName = "VolumeDialogViewBinder",
-                minWindowLifecycleState = WindowLifecycleState.ATTACHED,
-                factory = { dialogViewModelFactory.create() },
-            ) { viewModel ->
-                animateVisibility(root, dialog, viewModel.dialogVisibilityModel)
 
-                viewModel.dialogTitle.onEach { dialog.window?.setTitle(it) }.launchIn(this)
-                viewModel.motionState
-                    .scan(0) { acc, motionState ->
-                        // don't animate the initial state
-                        root.transitionToState(motionState, animate = acc != 0)
-                        acc + 1
-                    }
-                    .launchIn(this)
+        animateVisibility(root, dialog, viewModel.dialogVisibilityModel)
 
-                launch { root.viewTreeObserver.computeInternalInsetsListener(root) }
-
-                awaitCancellation()
+        viewModel.dialogTitle.onEach { dialog.window?.setTitle(it) }.launchIn(this)
+        viewModel.motionState
+            .scan(0) { acc, motionState ->
+                // don't animate the initial state
+                root.transitionToState(motionState, animate = acc != 0)
+                acc + 1
             }
-        }
-        volumeDialogRingerViewBinder.bind(root)
-        slidersViewBinder.bind(root)
-        settingsButtonViewBinder.bind(root)
+            .launchIn(this)
+
+        launch { root.viewTreeObserver.computeInternalInsetsListener(root) }
+
+        with(volumeDialogRingerViewBinder) { bind(root) }
+        with(slidersViewBinder) { bind(root) }
+        with(settingsButtonViewBinder) { bind(root) }
     }
 
     private fun CoroutineScope.animateVisibility(
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogPluginViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogPluginViewModel.kt
index e858cfe..ff525f46 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogPluginViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogPluginViewModel.kt
@@ -17,14 +17,14 @@
 package com.android.systemui.volume.dialog.ui.viewmodel
 
 import com.android.systemui.volume.Events
-import com.android.systemui.volume.dialog.dagger.VolumeDialogComponent
+import com.android.systemui.volume.dialog.VolumeDialog
 import com.android.systemui.volume.dialog.dagger.scope.VolumeDialogPluginScope
 import com.android.systemui.volume.dialog.domain.interactor.VolumeDialogVisibilityInteractor
 import com.android.systemui.volume.dialog.shared.VolumeDialogLogger
 import com.android.systemui.volume.dialog.shared.model.VolumeDialogVisibilityModel
 import javax.inject.Inject
+import javax.inject.Provider
 import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.cancel
 import kotlinx.coroutines.coroutineScope
 import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.mapLatest
@@ -34,8 +34,8 @@
 class VolumeDialogPluginViewModel
 @Inject
 constructor(
-    private val componentFactory: VolumeDialogComponent.Factory,
     private val dialogVisibilityInteractor: VolumeDialogVisibilityInteractor,
+    private val volumeDialogProvider: Provider<VolumeDialog>,
     private val logger: VolumeDialogLogger,
 ) {
 
@@ -45,7 +45,7 @@
                 .mapLatest { visibilityModel ->
                     with(visibilityModel) {
                         if (this is VolumeDialogVisibilityModel.Visible) {
-                            showDialog(componentFactory)
+                            showDialog()
                             Events.writeEvent(Events.EVENT_SHOW_DIALOG, reason, keyguardLocked)
                             logger.onShow(reason)
                         }
@@ -59,16 +59,14 @@
         }
     }
 
-    private suspend fun showDialog(componentFactory: VolumeDialogComponent.Factory): Unit =
-        coroutineScope {
-            val volumeDialogComponent: VolumeDialogComponent = componentFactory.create(this)
-            val dialog =
-                volumeDialogComponent.volumeDialog().apply {
-                    setOnDismissListener {
-                        volumeDialogComponent.coroutineScope().cancel()
-                        dialogVisibilityInteractor.dismissDialog(Events.DISMISS_REASON_UNKNOWN)
-                    }
+    private fun showDialog() {
+        volumeDialogProvider
+            .get()
+            .apply {
+                setOnDismissListener {
+                    dialogVisibilityInteractor.dismissDialog(Events.DISMISS_REASON_UNKNOWN)
                 }
-            dialog.show()
-        }
+            }
+            .show()
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogViewModel.kt
index 0352799..7a6ede4 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogViewModel.kt
@@ -23,6 +23,7 @@
 import com.android.systemui.statusbar.policy.DevicePostureController
 import com.android.systemui.statusbar.policy.devicePosture
 import com.android.systemui.statusbar.policy.onConfigChanged
+import com.android.systemui.volume.dialog.dagger.scope.VolumeDialogScope
 import com.android.systemui.volume.dialog.domain.interactor.VolumeDialogStateInteractor
 import com.android.systemui.volume.dialog.domain.interactor.VolumeDialogVisibilityInteractor
 import com.android.systemui.volume.dialog.shared.model.VolumeDialogStateModel
@@ -30,9 +31,7 @@
 import com.android.systemui.volume.dialog.shared.model.streamLabel
 import com.android.systemui.volume.dialog.sliders.domain.interactor.VolumeDialogSlidersInteractor
 import com.android.systemui.volume.dialog.sliders.domain.model.VolumeDialogSliderType
-import dagger.assisted.AssistedFactory
-import dagger.assisted.AssistedInject
-import kotlinx.coroutines.ExperimentalCoroutinesApi
+import javax.inject.Inject
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.filterNotNull
@@ -40,9 +39,9 @@
 import kotlinx.coroutines.flow.onStart
 
 /** Provides a state for the Volume Dialog. */
-@OptIn(ExperimentalCoroutinesApi::class)
+@VolumeDialogScope
 class VolumeDialogViewModel
-@AssistedInject
+@Inject
 constructor(
     private val context: Context,
     dialogVisibilityInteractor: VolumeDialogVisibilityInteractor,
@@ -84,9 +83,4 @@
         val isHalfOpen = devicePosture == DevicePostureController.DEVICE_POSTURE_HALF_OPENED
         return isLandscape && isHalfOpen
     }
-
-    @AssistedFactory
-    interface Factory {
-        fun create(): VolumeDialogViewModel
-    }
 }