Merge changes I1818de4e,If8033432 into main
* changes:
Make ViewModels consistent in terms of using ExclusiveActivateable
Add Volume Dialog window title based on the currently active slider.
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 7476c6a..097a60f 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/VolumeDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/VolumeDialog.kt
@@ -25,20 +25,20 @@
import com.android.systemui.res.R
import com.android.systemui.volume.Events
import com.android.systemui.volume.dialog.domain.interactor.VolumeDialogVisibilityInteractor
-import com.android.systemui.volume.dialog.ui.binder.VolumeDialogBinder
+import com.android.systemui.volume.dialog.ui.binder.VolumeDialogViewBinder
import javax.inject.Inject
class VolumeDialog
@Inject
constructor(
@Application context: Context,
- private val dialogBinder: VolumeDialogBinder,
+ private val viewBinder: VolumeDialogViewBinder,
private val visibilityInteractor: VolumeDialogVisibilityInteractor,
) : Dialog(ContextThemeWrapper(context, R.style.volume_dialog_theme)) {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- dialogBinder.bind(this)
+ viewBinder.bind(this)
}
/**
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 1a19806..b912361 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.launchTraced as launch
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.plugins.VolumeDialog
import com.android.systemui.volume.dialog.dagger.VolumeDialogPluginComponent
@@ -23,7 +24,6 @@
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.coroutineScope
-import com.android.app.tracing.coroutines.launchTraced as launch
class VolumeDialogPlugin
@Inject
@@ -33,19 +33,22 @@
) : VolumeDialog {
private var job: Job? = null
+ private var pluginComponent: VolumeDialogPluginComponent? = null
override fun init(windowType: Int, callback: VolumeDialog.Callback?) {
job =
applicationCoroutineScope.launch {
coroutineScope {
- val component = volumeDialogPluginComponentFactory.create(this)
-
- component.viewModel().activate()
+ pluginComponent =
+ volumeDialogPluginComponentFactory.create(this).also {
+ it.viewModel().launchVolumeDialog()
+ }
}
}
}
override fun destroy() {
job?.cancel()
+ pluginComponent = null
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/domain/interactor/VolumeDialogVisibilityInteractor.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/domain/interactor/VolumeDialogVisibilityInteractor.kt
index fb108c5..7307807 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/domain/interactor/VolumeDialogVisibilityInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/domain/interactor/VolumeDialogVisibilityInteractor.kt
@@ -17,6 +17,7 @@
package com.android.systemui.volume.dialog.domain.interactor
import android.annotation.SuppressLint
+import com.android.systemui.plugins.VolumeDialogController
import com.android.systemui.volume.Events
import com.android.systemui.volume.dialog.dagger.scope.VolumeDialogPlugin
import com.android.systemui.volume.dialog.dagger.scope.VolumeDialogPluginScope
@@ -34,11 +35,14 @@
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.mapLatest
import kotlinx.coroutines.flow.mapNotNull
import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.flow.stateIn
private val MAX_DIALOG_SHOW_TIME: Duration = 3.seconds
@@ -57,11 +61,16 @@
callbacksInteractor: VolumeDialogCallbacksInteractor,
private val tracer: VolumeTracer,
private val repository: VolumeDialogVisibilityRepository,
+ private val controller: VolumeDialogController,
) {
@SuppressLint("SharedFlowCreation")
private val mutableDismissDialogEvents = MutableSharedFlow<Unit>(extraBufferCapacity = 1)
- val dialogVisibility: Flow<VolumeDialogVisibilityModel> = repository.dialogVisibility
+ val dialogVisibility: Flow<VolumeDialogVisibilityModel> =
+ repository.dialogVisibility
+ .onEach { controller.notifyVisible(it is Visible) }
+ .stateIn(coroutineScope, SharingStarted.Eagerly, null)
+ .filterNotNull()
init {
merge(
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/settings/ui/binder/VolumeDialogSettingsButtonViewBinder.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/settings/ui/binder/VolumeDialogSettingsButtonViewBinder.kt
index b2f6cb3..2e1f82d 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/settings/ui/binder/VolumeDialogSettingsButtonViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/settings/ui/binder/VolumeDialogSettingsButtonViewBinder.kt
@@ -26,6 +26,8 @@
import com.android.systemui.volume.dialog.settings.ui.viewmodel.VolumeDialogSettingsButtonViewModel
import javax.inject.Inject
import kotlinx.coroutines.awaitCancellation
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
@VolumeDialogScope
class VolumeDialogSettingsButtonViewBinder
@@ -42,7 +44,12 @@
factory = { viewModelFactory.create() },
) { viewModel ->
setSnapshotBinding {
- visibility = if (viewModel.isVisible) View.VISIBLE else View.GONE
+ viewModel.isVisible
+ .onEach { isVisible ->
+ visibility = if (isVisible) View.VISIBLE else View.GONE
+ }
+ .launchIn(this)
+
button.setOnClickListener { viewModel.onButtonClicked() }
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/settings/ui/viewmodel/VolumeDialogSettingsButtonViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/settings/ui/viewmodel/VolumeDialogSettingsButtonViewModel.kt
index 2acc33b..015d773 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/settings/ui/viewmodel/VolumeDialogSettingsButtonViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/settings/ui/viewmodel/VolumeDialogSettingsButtonViewModel.kt
@@ -16,9 +16,6 @@
package com.android.systemui.volume.dialog.settings.ui.viewmodel
-import androidx.compose.runtime.getValue
-import com.android.systemui.lifecycle.ExclusiveActivatable
-import com.android.systemui.lifecycle.Hydrator
import com.android.systemui.volume.dialog.dagger.scope.VolumeDialogScope
import com.android.systemui.volume.dialog.settings.domain.VolumeDialogSettingsButtonInteractor
import dagger.assisted.AssistedFactory
@@ -26,15 +23,9 @@
class VolumeDialogSettingsButtonViewModel
@AssistedInject
-constructor(private val interactor: VolumeDialogSettingsButtonInteractor) : ExclusiveActivatable() {
+constructor(private val interactor: VolumeDialogSettingsButtonInteractor) {
- private val hydrator = Hydrator("VolumeDialog_settings_button")
-
- val isVisible by hydrator.hydratedStateOf("isVisible", interactor.isVisible)
-
- override suspend fun onActivated(): Nothing {
- hydrator.activate()
- }
+ val isVisible = interactor.isVisible
fun onButtonClicked() {
interactor.onButtonClicked()
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/shared/model/VolumeDialogStreamModel.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/shared/model/VolumeDialogStreamModel.kt
index be3cd97..cec58c3 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/shared/model/VolumeDialogStreamModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/shared/model/VolumeDialogStreamModel.kt
@@ -16,6 +16,7 @@
package com.android.systemui.volume.dialog.shared.model
+import android.content.Context
import androidx.annotation.StringRes
import com.android.systemui.plugins.VolumeDialogController
@@ -29,7 +30,9 @@
val levelMax: Int = 0,
val muted: Boolean = false,
val muteSupported: Boolean = false,
+ /** You likely need to use [streamLabel] instead. */
@StringRes val name: Int = 0,
+ /** You likely need to use [streamLabel] instead. */
val remoteLabel: String? = null,
val routedToBluetooth: Boolean = false,
) {
@@ -51,3 +54,10 @@
routedToBluetooth = legacyState.routedToBluetooth,
)
}
+
+fun VolumeDialogStreamModel.streamLabel(context: Context): String {
+ if (remoteLabel != null) {
+ return remoteLabel
+ }
+ return context.resources.getString(name)
+}
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 f486fe1..0a4e3f4 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
@@ -23,14 +23,14 @@
import androidx.compose.ui.util.fastForEachIndexed
import com.android.systemui.lifecycle.WindowLifecycleState
import com.android.systemui.lifecycle.repeatWhenAttached
-import com.android.systemui.lifecycle.setSnapshotBinding
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.ui.viewmodel.VolumeDialogSlidersViewModel
import javax.inject.Inject
import kotlin.math.abs
-import kotlinx.coroutines.awaitCancellation
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
@VolumeDialogScope
class VolumeDialogSlidersViewBinder
@@ -48,20 +48,20 @@
minWindowLifecycleState = WindowLifecycleState.ATTACHED,
factory = { viewModelFactory.create() },
) { viewModel ->
- setSnapshotBinding {
- viewModel.uiModel?.sliderViewBinder?.bind(volumeDialog)
+ viewModel.sliders
+ .onEach { uiModel ->
+ uiModel.sliderViewBinder.bind(volumeDialog)
- val floatingSliderViewBinders =
- viewModel.uiModel?.floatingSliderViewBinders ?: emptyList()
- floatingSlidersContainer.ensureChildCount(
- viewLayoutId = R.layout.volume_dialog_slider_floating,
- count = floatingSliderViewBinders.size,
- )
- floatingSliderViewBinders.fastForEachIndexed { index, viewBinder ->
- viewBinder.bind(floatingSlidersContainer.getChildAt(index))
+ val floatingSliderViewBinders = uiModel.floatingSliderViewBinders
+ floatingSlidersContainer.ensureChildCount(
+ viewLayoutId = R.layout.volume_dialog_slider_floating,
+ count = floatingSliderViewBinders.size,
+ )
+ floatingSliderViewBinders.fastForEachIndexed { index, viewBinder ->
+ viewBinder.bind(floatingSlidersContainer.getChildAt(index))
+ }
}
- }
- awaitCancellation()
+ .launchIn(this)
}
}
}
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 22cf89f..b5b292f 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
@@ -16,9 +16,6 @@
package com.android.systemui.volume.dialog.sliders.ui.viewmodel
-import androidx.compose.runtime.getValue
-import com.android.systemui.lifecycle.ExclusiveActivatable
-import com.android.systemui.lifecycle.Hydrator
import com.android.systemui.volume.dialog.dagger.scope.VolumeDialog
import com.android.systemui.volume.dialog.sliders.domain.interactor.VolumeDialogSliderInteractor
import com.android.systemui.volume.dialog.sliders.domain.interactor.VolumeDialogSlidersInteractor
@@ -27,9 +24,10 @@
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
-import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
@@ -41,10 +39,9 @@
private val sliderInteractorFactory: VolumeDialogSliderInteractor.Factory,
private val sliderViewModelFactory: VolumeDialogSliderViewModel.Factory,
private val sliderViewBinderFactory: VolumeDialogSliderViewBinder.Factory,
-) : ExclusiveActivatable() {
+) {
- private val hydrator = Hydrator("VolumeDialogSlidersViewModel")
- private val slidersStateFlow: StateFlow<VolumeDialogSliderUiModel?> =
+ val sliders: Flow<VolumeDialogSliderUiModel> =
slidersInteractor.sliders
.distinctUntilChanged()
.map { slidersModel ->
@@ -55,13 +52,7 @@
)
}
.stateIn(coroutineScope, SharingStarted.Eagerly, null)
-
- val uiModel: VolumeDialogSliderUiModel? by
- hydrator.hydratedStateOf("VolumeDialogSlidersViewModel#uiModel", slidersStateFlow)
-
- override suspend fun onActivated(): Nothing {
- hydrator.activate()
- }
+ .filterNotNull()
private fun createSliderViewBinder(type: VolumeDialogSliderType): VolumeDialogSliderViewBinder =
sliderViewBinderFactory.create {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogResourcesViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/VolumeDialogResources.kt
similarity index 95%
rename from packages/SystemUI/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogResourcesViewModel.kt
rename to packages/SystemUI/src/com/android/systemui/volume/dialog/ui/VolumeDialogResources.kt
index da9be98..e5cf62b 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogResourcesViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/VolumeDialogResources.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.volume.dialog.ui.viewmodel
+package com.android.systemui.volume.dialog.ui
import android.content.Context
import android.content.res.Resources
@@ -41,7 +41,7 @@
* Consume or use [kotlinx.coroutines.flow.first] to get the value.
*/
@VolumeDialogScope
-class VolumeDialogResourcesViewModel
+class VolumeDialogResources
@Inject
constructor(
@VolumeDialog private val coroutineScope: CoroutineScope,
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/binder/VolumeDialogBinder.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/binder/VolumeDialogBinder.kt
deleted file mode 100644
index cd535e4..0000000
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/binder/VolumeDialogBinder.kt
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (C) 2024 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.volume.dialog.ui.binder
-
-import android.app.Dialog
-import android.graphics.Color
-import android.graphics.PixelFormat
-import android.graphics.drawable.ColorDrawable
-import android.view.View
-import android.view.ViewGroup
-import android.view.Window
-import android.view.WindowManager
-import com.android.systemui.res.R
-import com.android.systemui.volume.dialog.dagger.scope.VolumeDialog
-import com.android.systemui.volume.dialog.dagger.scope.VolumeDialogScope
-import com.android.systemui.volume.dialog.ringer.ui.binder.VolumeDialogRingerViewBinder
-import com.android.systemui.volume.dialog.settings.ui.binder.VolumeDialogSettingsButtonViewBinder
-import com.android.systemui.volume.dialog.sliders.ui.VolumeDialogSlidersViewBinder
-import com.android.systemui.volume.dialog.ui.viewmodel.VolumeDialogGravityViewModel
-import javax.inject.Inject
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.flow.launchIn
-import kotlinx.coroutines.flow.onEach
-
-/** Binds the Volume Dialog itself. */
-@VolumeDialogScope
-class VolumeDialogBinder
-@Inject
-constructor(
- @VolumeDialog private val coroutineScope: CoroutineScope,
- private val volumeDialogViewBinder: VolumeDialogViewBinder,
- private val slidersViewBinder: VolumeDialogSlidersViewBinder,
- private val volumeDialogRingerViewBinder: VolumeDialogRingerViewBinder,
- private val settingsButtonViewBinder: VolumeDialogSettingsButtonViewBinder,
- private val gravityViewModel: VolumeDialogGravityViewModel,
-) {
-
- fun bind(dialog: Dialog) {
- with(dialog) {
- setupWindow(window!!)
- dialog.setContentView(R.layout.volume_dialog)
- dialog.setCanceledOnTouchOutside(true)
-
- with(dialog.requireViewById<View>(R.id.volume_dialog_container)) {
- volumeDialogRingerViewBinder.bind(this)
- slidersViewBinder.bind(this)
- settingsButtonViewBinder.bind(this)
- volumeDialogViewBinder.bind(dialog, this)
- }
- }
- }
-
- /** Configures [Window] for the [Dialog]. */
- private fun setupWindow(window: Window) =
- with(window) {
- clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND)
- addFlags(
- WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or
- WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL or
- WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH or
- WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED
- )
- addPrivateFlags(WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY)
-
- requestFeature(Window.FEATURE_NO_TITLE)
- setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
- setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY)
- setWindowAnimations(-1)
- setFormat(PixelFormat.TRANSLUCENT)
-
- attributes =
- attributes.apply {
- title = "VolumeDialog" // Not the same as Window#setTitle
- }
- setLayout(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)
-
- gravityViewModel.dialogGravity.onEach { window.setGravity(it) }.launchIn(coroutineScope)
- }
-}
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 23e6eac..78eabb2 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
@@ -17,19 +17,30 @@
package com.android.systemui.volume.dialog.ui.binder
import android.app.Dialog
+import android.graphics.Color
+import android.graphics.PixelFormat
+import android.graphics.drawable.ColorDrawable
import android.view.Gravity
import android.view.View
+import android.view.ViewGroup
+import android.view.Window
+import android.view.WindowManager
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.volume.SystemUIInterpolators
+import com.android.systemui.volume.dialog.dagger.scope.VolumeDialog
import com.android.systemui.volume.dialog.dagger.scope.VolumeDialogScope
+import com.android.systemui.volume.dialog.ringer.ui.binder.VolumeDialogRingerViewBinder
+import com.android.systemui.volume.dialog.settings.ui.binder.VolumeDialogSettingsButtonViewBinder
import com.android.systemui.volume.dialog.shared.model.VolumeDialogVisibilityModel
+import com.android.systemui.volume.dialog.sliders.ui.VolumeDialogSlidersViewBinder
+import com.android.systemui.volume.dialog.ui.VolumeDialogResources
import com.android.systemui.volume.dialog.ui.utils.JankListenerFactory
import com.android.systemui.volume.dialog.ui.utils.suspendAnimate
import com.android.systemui.volume.dialog.ui.viewmodel.VolumeDialogGravityViewModel
-import com.android.systemui.volume.dialog.ui.viewmodel.VolumeDialogResourcesViewModel
import com.android.systemui.volume.dialog.ui.viewmodel.VolumeDialogViewModel
import com.android.systemui.volume.dialog.utils.VolumeTracer
import javax.inject.Inject
@@ -40,6 +51,7 @@
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.mapLatest
+import kotlinx.coroutines.flow.onEach
/** Binds the root view of the Volume Dialog. */
@OptIn(ExperimentalCoroutinesApi::class)
@@ -47,14 +59,20 @@
class VolumeDialogViewBinder
@Inject
constructor(
- private val volumeResources: VolumeDialogResourcesViewModel,
+ private val volumeResources: VolumeDialogResources,
private val gravityViewModel: VolumeDialogGravityViewModel,
private val viewModelFactory: VolumeDialogViewModel.Factory,
private val jankListenerFactory: JankListenerFactory,
private val tracer: VolumeTracer,
+ @VolumeDialog private val coroutineScope: CoroutineScope,
+ private val volumeDialogRingerViewBinder: VolumeDialogRingerViewBinder,
+ private val slidersViewBinder: VolumeDialogSlidersViewBinder,
+ private val settingsButtonViewBinder: VolumeDialogSettingsButtonViewBinder,
) {
- fun bind(dialog: Dialog, view: View) {
+ fun bind(dialog: Dialog) {
+ setupDialog(dialog)
+ val view: View = dialog.requireViewById(R.id.volume_dialog_container)
view.alpha = 0f
view.repeatWhenAttached {
view.viewModel(
@@ -62,11 +80,46 @@
minWindowLifecycleState = WindowLifecycleState.ATTACHED,
factory = { viewModelFactory.create() },
) { viewModel ->
+ viewModel.dialogTitle.onEach { dialog.window?.setTitle(it) }.launchIn(this)
+
animateVisibility(view, dialog, viewModel.dialogVisibilityModel)
awaitCancellation()
}
}
+ volumeDialogRingerViewBinder.bind(view)
+ slidersViewBinder.bind(view)
+ settingsButtonViewBinder.bind(view)
+ }
+
+ /** Configures [Window] for the [Dialog]. */
+ private fun setupDialog(dialog: Dialog) {
+ with(dialog.window!!) {
+ clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND)
+ addFlags(
+ WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or
+ WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL or
+ WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH or
+ WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED
+ )
+ addPrivateFlags(WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY)
+
+ requestFeature(Window.FEATURE_NO_TITLE)
+ setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
+ setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY)
+ setWindowAnimations(-1)
+ setFormat(PixelFormat.TRANSLUCENT)
+
+ attributes =
+ attributes.apply {
+ title = "VolumeDialog" // Not the same as Window#setTitle
+ }
+ setLayout(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)
+
+ gravityViewModel.dialogGravity.onEach { setGravity(it) }.launchIn(coroutineScope)
+ }
+ dialog.setContentView(R.layout.volume_dialog)
+ dialog.setCanceledOnTouchOutside(true)
}
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 f336d46..e858cfe 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
@@ -16,8 +16,6 @@
package com.android.systemui.volume.dialog.ui.viewmodel
-import com.android.systemui.lifecycle.ExclusiveActivatable
-import com.android.systemui.plugins.VolumeDialogController
import com.android.systemui.volume.Events
import com.android.systemui.volume.dialog.dagger.VolumeDialogComponent
import com.android.systemui.volume.dialog.dagger.scope.VolumeDialogPluginScope
@@ -26,12 +24,10 @@
import com.android.systemui.volume.dialog.shared.model.VolumeDialogVisibilityModel
import javax.inject.Inject
import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.awaitCancellation
import kotlinx.coroutines.cancel
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.mapLatest
-import kotlinx.coroutines.flow.onEach
@OptIn(ExperimentalCoroutinesApi::class)
@VolumeDialogPluginScope
@@ -40,18 +36,18 @@
constructor(
private val componentFactory: VolumeDialogComponent.Factory,
private val dialogVisibilityInteractor: VolumeDialogVisibilityInteractor,
- private val controller: VolumeDialogController,
private val logger: VolumeDialogLogger,
-) : ExclusiveActivatable() {
+) {
- override suspend fun onActivated(): Nothing {
+ suspend fun launchVolumeDialog() {
coroutineScope {
dialogVisibilityInteractor.dialogVisibility
- .onEach { controller.notifyVisible(it is VolumeDialogVisibilityModel.Visible) }
.mapLatest { visibilityModel ->
with(visibilityModel) {
if (this is VolumeDialogVisibilityModel.Visible) {
- showDialog(reason, keyguardLocked)
+ showDialog(componentFactory)
+ Events.writeEvent(Events.EVENT_SHOW_DIALOG, reason, keyguardLocked)
+ logger.onShow(reason)
}
if (this is VolumeDialogVisibilityModel.Dismissed) {
Events.writeEvent(Events.EVENT_DISMISS_DIALOG, reason)
@@ -61,24 +57,18 @@
}
.launchIn(this)
}
- awaitCancellation()
}
- suspend fun showDialog(reason: Int, keyguardLocked: Boolean): Unit = coroutineScope {
- logger.onShow(reason)
-
- controller.notifyVisible(true)
-
- val volumeDialogComponent: VolumeDialogComponent = componentFactory.create(this)
- val dialog =
- volumeDialogComponent.volumeDialog().apply {
- setOnDismissListener {
- volumeDialogComponent.coroutineScope().cancel()
- dialogVisibilityInteractor.dismissDialog(Events.DISMISS_REASON_UNKNOWN)
+ 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)
+ }
}
- }
- dialog.show()
-
- Events.writeEvent(Events.EVENT_SHOW_DIALOG, reason, keyguardLocked)
- }
+ dialog.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 84c837c..9be669f 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
@@ -16,25 +16,40 @@
package com.android.systemui.volume.dialog.ui.viewmodel
-import com.android.systemui.lifecycle.ExclusiveActivatable
+import android.content.Context
+import com.android.systemui.res.R
import com.android.systemui.volume.dialog.domain.interactor.VolumeDialogVisibilityInteractor
import com.android.systemui.volume.dialog.shared.model.VolumeDialogVisibilityModel
+import com.android.systemui.volume.dialog.shared.model.streamLabel
+import com.android.systemui.volume.dialog.sliders.domain.interactor.VolumeDialogSliderInteractor
+import com.android.systemui.volume.dialog.sliders.domain.interactor.VolumeDialogSlidersInteractor
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
-import kotlinx.coroutines.awaitCancellation
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.map
/** Provides a state for the Volume Dialog. */
+@OptIn(ExperimentalCoroutinesApi::class)
class VolumeDialogViewModel
@AssistedInject
-constructor(dialogVisibilityInteractor: VolumeDialogVisibilityInteractor) : ExclusiveActivatable() {
+constructor(
+ private val context: Context,
+ dialogVisibilityInteractor: VolumeDialogVisibilityInteractor,
+ volumeDialogSlidersInteractor: VolumeDialogSlidersInteractor,
+ private val volumeDialogSliderInteractorFactory: VolumeDialogSliderInteractor.Factory,
+) {
val dialogVisibilityModel: Flow<VolumeDialogVisibilityModel> =
dialogVisibilityInteractor.dialogVisibility
-
- override suspend fun onActivated(): Nothing {
- awaitCancellation()
- }
+ val dialogTitle: Flow<String> =
+ volumeDialogSlidersInteractor.sliders.flatMapLatest { slidersModel ->
+ val interactor = volumeDialogSliderInteractorFactory.create(slidersModel.slider)
+ interactor.slider.map { sliderModel ->
+ context.getString(R.string.volume_dialog_title, sliderModel.streamLabel(context))
+ }
+ }
@AssistedFactory
interface Factory {
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/domain/interactor/VolumeDialogVisibilityInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/domain/interactor/VolumeDialogVisibilityInteractorKosmos.kt
index 7376c7f..0d2aa4c 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/domain/interactor/VolumeDialogVisibilityInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/domain/interactor/VolumeDialogVisibilityInteractorKosmos.kt
@@ -18,6 +18,7 @@
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.plugins.volumeDialogController
import com.android.systemui.volume.dialog.data.repository.volumeDialogVisibilityRepository
import com.android.systemui.volume.dialog.utils.volumeTracer
@@ -28,5 +29,6 @@
volumeDialogCallbacksInteractor,
volumeTracer,
volumeDialogVisibilityRepository,
+ volumeDialogController,
)
}