Add Volume Dialog window title based on the currently active slider.
Flag: com.android.systemui.volume_redesign
Bug: 369994090
Test: manual on the foldable
Change-Id: If80334326b0ec37b8ff850196dd710dcb97aa02d
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/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/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..f9c7bc0 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,15 +17,26 @@
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.utils.JankListenerFactory
import com.android.systemui.volume.dialog.ui.utils.suspendAnimate
import com.android.systemui.volume.dialog.ui.viewmodel.VolumeDialogGravityViewModel
@@ -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)
@@ -52,9 +64,15 @@
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/VolumeDialogViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogViewModel.kt
index 84c837c..e9786d0 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,21 +16,42 @@
package com.android.systemui.volume.dialog.ui.viewmodel
+import android.content.Context
import com.android.systemui.lifecycle.ExclusiveActivatable
+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.ExperimentalCoroutinesApi
import kotlinx.coroutines.awaitCancellation
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,
+) : ExclusiveActivatable() {
val dialogVisibilityModel: Flow<VolumeDialogVisibilityModel> =
dialogVisibilityInteractor.dialogVisibility
+ 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))
+ }
+ }
override suspend fun onActivated(): Nothing {
awaitCancellation()