diff options
13 files changed, 186 insertions, 211 deletions
diff --git a/packages/SystemUI/res/drawable/volume_background_top.xml b/packages/SystemUI/res/drawable/volume_background_top.xml index 75849beeb016..132572a41a36 100644 --- a/packages/SystemUI/res/drawable/volume_background_top.xml +++ b/packages/SystemUI/res/drawable/volume_background_top.xml @@ -17,7 +17,6 @@ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"> <item> <shape> - <size android:width="@dimen/volume_dialog_width" /> <solid android:color="?androidprv:attr/materialColorSurface" /> <corners android:topLeftRadius="@dimen/volume_dialog_background_corner_radius" android:topRightRadius="@dimen/volume_dialog_background_corner_radius"/> diff --git a/packages/SystemUI/res/drawable/volume_dialog_spacer.xml b/packages/SystemUI/res/drawable/volume_dialog_spacer.xml deleted file mode 100644 index 3c60784cf6b6..000000000000 --- a/packages/SystemUI/res/drawable/volume_dialog_spacer.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?><!-- - 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. ---> - -<shape xmlns:android="http://schemas.android.com/apk/res/android" - android:shape="rectangle"> - <size - android:width="@dimen/volume_dialog_spacing" - android:height="@dimen/volume_dialog_spacing" /> - <solid android:color="@color/transparent" /> -</shape> diff --git a/packages/SystemUI/res/layout/volume_dialog.xml b/packages/SystemUI/res/layout/volume_dialog.xml index f187ce62ddb2..694357d534fb 100644 --- a/packages/SystemUI/res/layout/volume_dialog.xml +++ b/packages/SystemUI/res/layout/volume_dialog.xml @@ -13,58 +13,70 @@ See the License for the specific language governing permissions and limitations under the License. --> -<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" +<androidx.constraintlayout.motion.widget.MotionLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/volume_dialog_root" android:layout_width="match_parent" - android:layout_height="match_parent"> + android:layout_height="match_parent" + app:layoutDescription="@xml/volume_dialog_scene"> - <LinearLayout - android:id="@+id/volume_dialog_container" + <View + android:id="@+id/volume_dialog_background" + android:layout_width="@dimen/volume_dialog_width" + android:layout_height="0dp" + android:layout_marginTop="@dimen/volume_dialog_background_vertical_margin" + android:layout_marginBottom="@dimen/volume_dialog_background_vertical_margin" + android:background="@drawable/volume_dialog_background" + app:layout_constraintBottom_toBottomOf="@id/volume_dialog_settings" + app:layout_constraintEnd_toEndOf="@id/volume_dialog_main_slider_container" + app:layout_constraintStart_toStartOf="@id/volume_dialog_main_slider_container" + app:layout_constraintTop_toTopOf="@id/volume_ringer_and_drawer_container" /> + + <include + android:id="@id/volume_ringer_and_drawer_container" + layout="@layout/volume_ringer_drawer" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_gravity="center_vertical|end" - android:divider="@drawable/volume_dialog_floating_sliders_spacer" - android:orientation="horizontal" - android:showDividers="middle|end|beginning"> - - <LinearLayout - android:id="@+id/volume_dialog_floating_sliders_container" - android:layout_width="wrap_content" - android:layout_height="match_parent" - android:divider="@drawable/volume_dialog_floating_sliders_spacer" - android:gravity="bottom" - android:orientation="horizontal" - android:paddingBottom="@dimen/volume_dialog_floating_sliders_bottom_padding" - android:showDividers="middle" /> + android:layout_marginBottom="@dimen/volume_dialog_components_spacing" + app:layout_constraintBottom_toTopOf="@id/volume_dialog_main_slider_container" + app:layout_constraintEnd_toEndOf="@id/volume_dialog_main_slider_container" + app:layout_constraintStart_toStartOf="@id/volume_dialog_main_slider_container" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintVertical_bias="1" /> - <LinearLayout - android:id="@+id/volume_dialog" - android:layout_width="@dimen/volume_dialog_width" - android:layout_height="wrap_content" - android:background="@drawable/volume_dialog_background" - android:clipChildren="false" - android:clipToOutline="false" - android:clipToPadding="false" - android:divider="@drawable/volume_dialog_spacer" - android:gravity="center_horizontal" - android:orientation="vertical" - android:paddingVertical="@dimen/volume_dialog_vertical_padding" - android:showDividers="middle"> + <include + android:id="@+id/volume_dialog_main_slider_container" + layout="@layout/volume_dialog_slider" /> - <include layout="@layout/volume_ringer_drawer" /> + <ImageButton + android:id="@+id/volume_dialog_settings" + android:layout_width="@dimen/volume_dialog_button_size" + android:layout_height="@dimen/volume_dialog_button_size" + android:layout_marginTop="@dimen/volume_dialog_components_spacing" + android:background="@drawable/ripple_drawable_20dp" + android:contentDescription="@string/accessibility_volume_settings" + android:soundEffectsEnabled="false" + android:src="@drawable/horizontal_ellipsis" + android:tint="?androidprv:attr/materialColorPrimary" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="@id/volume_dialog_main_slider_container" + app:layout_constraintStart_toStartOf="@id/volume_dialog_main_slider_container" + app:layout_constraintTop_toBottomOf="@id/volume_dialog_main_slider_container" + app:layout_constraintVertical_bias="0" /> - <include layout="@layout/volume_dialog_slider" /> + <LinearLayout + android:id="@+id/volume_dialog_floating_sliders_container" + android:layout_width="wrap_content" + android:layout_height="0dp" + android:layout_marginTop="@dimen/volume_dialog_floating_sliders_vertical_padding_negative" + android:layout_marginBottom="@dimen/volume_dialog_floating_sliders_vertical_padding_negative" + android:divider="@drawable/volume_dialog_floating_sliders_spacer" + android:gravity="bottom" + android:orientation="horizontal" + android:showDividers="middle|beginning|end" + app:layout_constraintBottom_toBottomOf="@id/volume_dialog_main_slider_container" + app:layout_constraintEnd_toStartOf="@id/volume_dialog_background" + app:layout_constraintTop_toTopOf="@id/volume_dialog_main_slider_container" /> - <ImageButton - android:id="@+id/volume_dialog_settings" - android:layout_width="@dimen/volume_dialog_button_size" - android:layout_height="@dimen/volume_dialog_button_size" - android:background="@drawable/ripple_drawable_20dp" - android:contentDescription="@string/accessibility_volume_settings" - android:soundEffectsEnabled="false" - android:src="@drawable/horizontal_ellipsis" - android:tint="?androidprv:attr/materialColorPrimary" /> - </LinearLayout> - </LinearLayout> -</FrameLayout>
\ No newline at end of file +</androidx.constraintlayout.motion.widget.MotionLayout>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/volume_ringer_drawer.xml b/packages/SystemUI/res/layout/volume_ringer_drawer.xml index 7c266e60b503..b71c4700c0fa 100644 --- a/packages/SystemUI/res/layout/volume_ringer_drawer.xml +++ b/packages/SystemUI/res/layout/volume_ringer_drawer.xml @@ -19,13 +19,10 @@ android:id="@+id/volume_ringer_and_drawer_container" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:gravity="center" - android:paddingLeft="@dimen/volume_dialog_ringer_horizontal_padding" - android:paddingRight="@dimen/volume_dialog_ringer_horizontal_padding" - android:layoutDirection="ltr" - android:clipToPadding="false" android:clipChildren="false" - android:background="@drawable/volume_background_top"> + android:clipToPadding="false" + android:gravity="center" + android:layoutDirection="ltr"> <!-- Drawer view, invisible by default. --> <FrameLayout @@ -37,10 +34,10 @@ <!-- View that is animated to a tapped ringer selection, so it appears selected. --> <FrameLayout android:id="@+id/volume_drawer_selection_background" - android:alpha="0.0" android:layout_width="@dimen/volume_dialog_ringer_drawer_button_size" android:layout_height="@dimen/volume_dialog_ringer_drawer_button_size" android:layout_gravity="bottom|right" + android:alpha="0.0" android:background="@drawable/volume_drawer_selection_bg" /> <LinearLayout @@ -65,7 +62,6 @@ android:background="@drawable/volume_drawer_selection_bg" android:contentDescription="@string/volume_ringer_change" android:gravity="center" - android:padding="@dimen/volume_dialog_ringer_horizontal_padding" android:src="@drawable/ic_volume_media" android:tint="?androidprv:attr/materialColorOnPrimary" /> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 7af005721e13..22d6b09fb890 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -2060,26 +2060,29 @@ <dimen name="contextual_edu_dialog_elevation">2dp</dimen> <!-- Volume start --> - <dimen name="volume_dialog_background_corner_radius">30dp</dimen> <dimen name="volume_dialog_width">60dp</dimen> - <dimen name="volume_dialog_vertical_padding">10dp</dimen> + + <dimen name="volume_dialog_background_corner_radius">30dp</dimen> + <dimen name="volume_dialog_background_vertical_margin">-10dp</dimen> + <dimen name="volume_dialog_components_spacing">8dp</dimen> <dimen name="volume_dialog_floating_sliders_spacing">8dp</dimen> <dimen name="volume_dialog_floating_sliders_vertical_padding">10dp</dimen> + <dimen name="volume_dialog_floating_sliders_vertical_padding_negative">-10dp</dimen> <dimen name="volume_dialog_floating_sliders_horizontal_padding">4dp</dimen> - <dimen name="volume_dialog_spacing">4dp</dimen> <dimen name="volume_dialog_button_size">48dp</dimen> - <dimen name="volume_dialog_floating_sliders_bottom_padding">48dp</dimen> <dimen name="volume_dialog_slider_width">52dp</dimen> <dimen name="volume_dialog_slider_height">254dp</dimen> - <dimen name="volume_panel_slice_vertical_padding">8dp</dimen> - <dimen name="volume_panel_slice_horizontal_padding">24dp</dimen> + <fraction name="volume_dialog_half_opened_bias">0.2</fraction> + + <dimen name="volume_dialog_background_square_corner_radius">12dp</dimen> - <dimen name="volume_dialog_ringer_horizontal_padding">10dp</dimen> <dimen name="volume_dialog_ringer_drawer_button_size">40dp</dimen> <dimen name="volume_dialog_ringer_drawer_button_icon_radius">10dp</dimen> - <dimen name="volume_dialog_background_square_corner_radius">12dp</dimen> <dimen name="volume_dialog_ringer_selected_button_background_radius">20dp</dimen> + + <dimen name="volume_panel_slice_vertical_padding">8dp</dimen> + <dimen name="volume_panel_slice_horizontal_padding">24dp</dimen> <!-- Volume end --> </resources> diff --git a/packages/SystemUI/res/xml/volume_dialog_constraint_set.xml b/packages/SystemUI/res/xml/volume_dialog_constraint_set.xml new file mode 100644 index 000000000000..9018e5b7ed92 --- /dev/null +++ b/packages/SystemUI/res/xml/volume_dialog_constraint_set.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="utf-8"?> +<ConstraintSet xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:id="@+id/volume_dialog_constraint_set"> + + <Constraint + android:id="@id/volume_dialog_main_slider_container" + android:layout_width="@dimen/volume_dialog_slider_width" + android:layout_height="@dimen/volume_dialog_slider_height" + android:layout_marginEnd="@dimen/volume_dialog_components_spacing" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintVertical_bias="0.5" /> +</ConstraintSet>
\ No newline at end of file diff --git a/packages/SystemUI/res/xml/volume_dialog_half_folded_constraint_set.xml b/packages/SystemUI/res/xml/volume_dialog_half_folded_constraint_set.xml new file mode 100644 index 000000000000..297c38873164 --- /dev/null +++ b/packages/SystemUI/res/xml/volume_dialog_half_folded_constraint_set.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="utf-8"?> +<ConstraintSet xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:id="@+id/volume_dialog_half_folded_constraint_set"> + + <Constraint + android:id="@id/volume_dialog_main_slider_container" + android:layout_width="@dimen/volume_dialog_slider_width" + android:layout_height="@dimen/volume_dialog_slider_height" + android:layout_marginEnd="@dimen/volume_dialog_components_spacing" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintVertical_bias="@fraction/volume_dialog_half_opened_bias" /> +</ConstraintSet>
\ No newline at end of file diff --git a/packages/SystemUI/res/xml/volume_dialog_scene.xml b/packages/SystemUI/res/xml/volume_dialog_scene.xml new file mode 100644 index 000000000000..b813474490bb --- /dev/null +++ b/packages/SystemUI/res/xml/volume_dialog_scene.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ 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. + --> + +<MotionScene xmlns:motion="http://schemas.android.com/apk/res-auto"> + + <Transition + motion:autoTransition="none" + motion:constraintSetEnd="@id/volume_dialog_half_folded_constraint_set" + motion:constraintSetStart="@id/volume_dialog_constraint_set" + motion:duration="150" /> + + <Include motion:constraintSet="@xml/volume_dialog_constraint_set" /> + <Include motion:constraintSet="@xml/volume_dialog_half_folded_constraint_set" /> +</MotionScene>
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/binder/VolumeDialogRingerViewBinder.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/binder/VolumeDialogRingerViewBinder.kt index 6816d35f7699..c4b028d7d98b 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/binder/VolumeDialogRingerViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/binder/VolumeDialogRingerViewBinder.kt @@ -49,7 +49,7 @@ constructor(private val viewModelFactory: VolumeDialogRingerDrawerViewModel.Fact val drawerContainer = requireViewById<View>(R.id.volume_drawer_container) val selectedButtonView = requireViewById<ImageButton>(R.id.volume_new_ringer_active_button) - val volumeDialogView = requireViewById<ViewGroup>(R.id.volume_dialog) + val volumeDialogBackgroundView = requireViewById<View>(R.id.volume_dialog_background) repeatWhenAttached { viewModel( traceName = "VolumeDialogRingerViewBinder", @@ -71,19 +71,17 @@ constructor(private val viewModelFactory: VolumeDialogRingerDrawerViewModel.Fact is RingerDrawerState.Initial -> { drawerContainer.visibility = View.GONE selectedButtonView.visibility = View.VISIBLE - volumeDialogView.setBackgroundResource( + volumeDialogBackgroundView.setBackgroundResource( R.drawable.volume_dialog_background ) } - is RingerDrawerState.Closed -> { drawerContainer.visibility = View.GONE selectedButtonView.visibility = View.VISIBLE - volumeDialogView.setBackgroundResource( + volumeDialogBackgroundView.setBackgroundResource( R.drawable.volume_dialog_background ) } - is RingerDrawerState.Open -> { drawerContainer.visibility = View.VISIBLE selectedButtonView.visibility = View.GONE @@ -91,17 +89,16 @@ constructor(private val viewModelFactory: VolumeDialogRingerDrawerViewModel.Fact uiModel.currentButtonIndex != uiModel.availableButtons.size - 1 ) { - volumeDialogView.setBackgroundResource( + volumeDialogBackgroundView.setBackgroundResource( R.drawable.volume_dialog_background_small_radius ) } } } } - is RingerViewModelState.Unavailable -> { drawerAndRingerContainer.visibility = View.GONE - volumeDialogView.setBackgroundResource( + volumeDialogBackgroundView.setBackgroundResource( R.drawable.volume_dialog_background ) } 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 a17c1e541b5e..9078f82d3e98 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 @@ -38,9 +38,10 @@ constructor(private val viewModelFactory: VolumeDialogSlidersViewModel.Factory) fun bind(view: View) { with(view) { - val volumeDialog: View = requireViewById(R.id.volume_dialog) 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", @@ -49,7 +50,7 @@ constructor(private val viewModelFactory: VolumeDialogSlidersViewModel.Factory) ) { viewModel -> viewModel.sliders .onEach { uiModel -> - uiModel.sliderComponent.sliderViewBinder().bind(volumeDialog) + uiModel.sliderComponent.sliderViewBinder().bind(mainSliderContainer) val floatingSliderViewBinders = uiModel.floatingSliderComponent floatingSlidersContainer.ensureChildCount( 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 d9a945cfedfd..f6c1743a4bea 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 @@ -19,13 +19,11 @@ package com.android.systemui.volume.dialog.ui.binder import android.app.Dialog import android.graphics.Rect import android.graphics.Region -import android.view.Gravity import android.view.View import android.view.ViewGroup import android.view.ViewTreeObserver import android.view.ViewTreeObserver.InternalInsetsInfo -import android.widget.FrameLayout -import androidx.annotation.GravityInt +import androidx.constraintlayout.motion.widget.MotionLayout import com.android.internal.view.RotationPolicy import com.android.systemui.lifecycle.WindowLifecycleState import com.android.systemui.lifecycle.repeatWhenAttached @@ -41,7 +39,6 @@ import com.android.systemui.volume.dialog.sliders.ui.VolumeDialogSlidersViewBind 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.VolumeDialogViewModel import com.android.systemui.volume.dialog.utils.VolumeTracer import javax.inject.Inject @@ -53,6 +50,7 @@ import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.mapLatest import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.flow.scan import kotlinx.coroutines.launch import kotlinx.coroutines.suspendCancellableCoroutine @@ -63,7 +61,6 @@ class VolumeDialogViewBinder @Inject constructor( private val volumeResources: VolumeDialogResources, - private val gravityViewModel: VolumeDialogGravityViewModel, private val dialogViewModelFactory: VolumeDialogViewModel.Factory, private val jankListenerFactory: JankListenerFactory, private val tracer: VolumeTracer, @@ -74,21 +71,23 @@ constructor( fun bind(dialog: Dialog) { // Root view of the Volume Dialog. - val root: ViewGroup = dialog.requireViewById(R.id.volume_dialog_root) - // Volume Dialog container view that contains the dialog itself without the floating sliders - val container: View = root.requireViewById(R.id.volume_dialog_container) - container.alpha = 0f - container.repeatWhenAttached { + 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(container, dialog, viewModel.dialogVisibilityModel) + animateVisibility(root, dialog, viewModel.dialogVisibilityModel) viewModel.dialogTitle.onEach { dialog.window?.setTitle(it) }.launchIn(this) - gravityViewModel.dialogGravity - .onEach { container.setLayoutGravity(it) } + viewModel.motionState + .scan(0) { acc, motionState -> + // don't animate the initial state + root.transitionToState(motionState, animate = acc != 0) + acc + 1 + } .launchIn(this) launch { root.viewTreeObserver.computeInternalInsetsListener(root) } @@ -130,15 +129,13 @@ constructor( .launchIn(this) } - private suspend fun calculateTranslationX(view: View): Float? { + private fun calculateTranslationX(view: View): Float? { return if (view.display.rotation == RotationPolicy.NATURAL_ROTATION) { - val dialogGravity = gravityViewModel.dialogGravity.first() - val isGravityLeft = (dialogGravity and Gravity.LEFT) == Gravity.LEFT - if (isGravityLeft) { + if (view.isLayoutRtl) { -1 } else { 1 - } * view.width / 2.0f + } * view.width / 2f } else { null } @@ -211,10 +208,11 @@ constructor( getBoundsInWindow(boundsRect, false) } - private fun View.setLayoutGravity(@GravityInt newGravity: Int) { - val frameLayoutParams = - layoutParams as? FrameLayout.LayoutParams - ?: error("View must be a child of a FrameLayout") - layoutParams = frameLayoutParams.apply { gravity = newGravity } + private fun MotionLayout.transitionToState(newState: Int, animate: Boolean) { + if (animate) { + transitionToState(newState) + } else { + jumpToState(newState) + } } } diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogGravityViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogGravityViewModel.kt deleted file mode 100644 index 112afb1debf5..000000000000 --- a/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogGravityViewModel.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.viewmodel - -import android.content.Context -import android.content.res.Configuration -import android.view.Gravity -import androidx.annotation.GravityInt -import com.android.systemui.dagger.qualifiers.Application -import com.android.systemui.dagger.qualifiers.UiBackground -import com.android.systemui.res.R -import com.android.systemui.statusbar.policy.ConfigurationController -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.VolumeDialog -import com.android.systemui.volume.dialog.dagger.scope.VolumeDialogScope -import javax.inject.Inject -import kotlin.coroutines.CoroutineContext -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.SharingStarted -import kotlinx.coroutines.flow.combine -import kotlinx.coroutines.flow.onEach -import kotlinx.coroutines.flow.stateIn -import kotlinx.coroutines.withContext - -/** Exposes dialog [GravityInt] for use in the UI layer. */ -@VolumeDialogScope -class VolumeDialogGravityViewModel -@Inject -constructor( - @Application private val context: Context, - @VolumeDialog private val coroutineScope: CoroutineScope, - @UiBackground private val uiBackgroundCoroutineContext: CoroutineContext, - configurationController: ConfigurationController, - private val devicePostureController: DevicePostureController, -) { - - @GravityInt private var originalGravity: Int = context.getAbsoluteGravity() - - val dialogGravity: Flow<Int> = - combine( - devicePostureController.devicePosture(), - configurationController.onConfigChanged.onEach { onConfigurationChanged() }, - ) { devicePosture, configuration -> - context.calculateGravity(devicePosture, configuration) - } - .stateIn( - scope = coroutineScope, - started = SharingStarted.Eagerly, - context.calculateGravity(), - ) - - private suspend fun onConfigurationChanged() { - withContext(uiBackgroundCoroutineContext) { originalGravity = context.getAbsoluteGravity() } - } - - @GravityInt - private fun Context.calculateGravity( - devicePosture: Int = devicePostureController.devicePosture, - config: Configuration = resources.configuration, - ): Int { - val isLandscape = config.orientation == Configuration.ORIENTATION_LANDSCAPE - val isHalfOpen = devicePosture == DevicePostureController.DEVICE_POSTURE_HALF_OPENED - val gravity = - if (isLandscape && isHalfOpen) { - originalGravity or Gravity.TOP - } else { - originalGravity - } - return getAbsoluteGravity(gravity) - } -} - -@GravityInt -private fun Context.getAbsoluteGravity( - gravity: Int = resources.getInteger(R.integer.volume_dialog_gravity) -): Int = with(resources) { Gravity.getAbsoluteGravity(gravity, configuration.layoutDirection) } 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 869a6a2e87d5..0352799916bc 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 @@ -17,7 +17,12 @@ package com.android.systemui.volume.dialog.ui.viewmodel import android.content.Context +import android.content.res.Configuration import com.android.systemui.res.R +import com.android.systemui.statusbar.policy.ConfigurationController +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.domain.interactor.VolumeDialogStateInteractor import com.android.systemui.volume.dialog.domain.interactor.VolumeDialogVisibilityInteractor import com.android.systemui.volume.dialog.shared.model.VolumeDialogStateModel @@ -32,6 +37,7 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.onStart /** Provides a state for the Volume Dialog. */ @OptIn(ExperimentalCoroutinesApi::class) @@ -42,8 +48,23 @@ constructor( dialogVisibilityInteractor: VolumeDialogVisibilityInteractor, volumeDialogSlidersInteractor: VolumeDialogSlidersInteractor, volumeDialogStateInteractor: VolumeDialogStateInteractor, + devicePostureController: DevicePostureController, + configurationController: ConfigurationController, ) { + val motionState: Flow<Int> = + combine( + devicePostureController.devicePosture(), + configurationController.onConfigChanged.onStart { + emit(context.resources.configuration) + }, + ) { devicePosture, configuration -> + if (shouldOffsetVolumeDialog(devicePosture, configuration)) { + R.id.volume_dialog_half_folded_constraint_set + } else { + R.id.volume_dialog_constraint_set + } + } val dialogVisibilityModel: Flow<VolumeDialogVisibilityModel> = dialogVisibilityInteractor.dialogVisibility val dialogTitle: Flow<String> = @@ -57,6 +78,13 @@ constructor( } .filterNotNull() + /** @return true when the foldable device screen curve is in the way of the volume dialog */ + private fun shouldOffsetVolumeDialog(devicePosture: Int, config: Configuration): Boolean { + val isLandscape = config.orientation == Configuration.ORIENTATION_LANDSCAPE + val isHalfOpen = devicePosture == DevicePostureController.DEVICE_POSTURE_HALF_OPENED + return isLandscape && isHalfOpen + } + @AssistedFactory interface Factory { fun create(): VolumeDialogViewModel |