Loading packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsPanelLayout.kt 0 → 100644 +61 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.systemui.qs.ui.composable import androidx.compose.foundation.layout.Arrangement.spacedBy import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @Composable fun QuickSettingsPanelLayout( brightness: @Composable () -> Unit, tiles: @Composable () -> Unit, media: @Composable () -> Unit, mediaInRow: Boolean, modifier: Modifier = Modifier, ) { if (mediaInRow) { Column( verticalArrangement = spacedBy(QuickSettingsShade.Dimensions.Padding), horizontalAlignment = Alignment.CenterHorizontally, modifier = modifier, ) { brightness() Row( horizontalArrangement = spacedBy(QuickSettingsShade.Dimensions.Padding), verticalAlignment = Alignment.CenterVertically, ) { Box(modifier = Modifier.weight(1f)) { tiles() } Box(modifier = Modifier.weight(1f)) { media() } } } } else { Column( verticalArrangement = spacedBy(QuickSettingsShade.Dimensions.Padding), horizontalAlignment = Alignment.CenterHorizontally, modifier = modifier, ) { brightness() tiles() media() } } } packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt +57 −151 Original line number Diff line number Diff line Loading @@ -16,17 +16,7 @@ package com.android.systemui.qs.ui.composable import androidx.activity.compose.BackHandler import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.core.animateDpAsState import androidx.compose.animation.core.animateFloatAsState import androidx.compose.animation.core.tween import androidx.compose.animation.expandVertically import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.animation.shrinkVertically import androidx.compose.animation.slideInVertically import androidx.compose.animation.slideOutVertically import androidx.compose.foundation.background import androidx.compose.foundation.clipScrollableContainer import androidx.compose.foundation.gestures.Orientation Loading @@ -36,7 +26,6 @@ import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.asPaddingValues import androidx.compose.foundation.layout.displayCutoutPadding import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height Loading @@ -51,7 +40,6 @@ import androidx.compose.foundation.verticalScroll import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.ui.Alignment Loading @@ -59,8 +47,6 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.CompositingStrategy import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.layout.Layout import androidx.compose.ui.layout.layoutId import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalLifecycleOwner Loading @@ -68,7 +54,6 @@ import androidx.compose.ui.res.colorResource import androidx.compose.ui.res.dimensionResource import androidx.compose.ui.unit.IntOffset import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.android.compose.animation.scene.ContentScope import com.android.compose.animation.scene.UserAction import com.android.compose.animation.scene.UserActionResult Loading Loading @@ -107,11 +92,9 @@ import com.android.systemui.res.R import com.android.systemui.scene.session.ui.composable.SaveableSession import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.scene.ui.composable.Scene import com.android.systemui.settings.brightness.ui.viewModel.BrightnessMirrorViewModel import com.android.systemui.shade.ui.composable.CollapsedShadeHeader import com.android.systemui.shade.ui.composable.ExpandedShadeHeader import com.android.systemui.shade.ui.composable.Shade import com.android.systemui.shade.ui.composable.ShadeHeader import com.android.systemui.shade.ui.viewmodel.ShadeHeaderViewModel import com.android.systemui.statusbar.notification.stack.ui.view.NotificationScrollView import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationsPlaceholderViewModel Loading Loading @@ -153,10 +136,6 @@ constructor( override fun ContentScope.Content(modifier: Modifier) { val viewModel = rememberViewModel("QuickSettingsScene-viewModel") { contentViewModelFactory.create() } val brightnessMirrorViewModel = rememberViewModel("QuickSettingsScene-brightnessMirrorViewModel") { viewModel.brightnessMirrorViewModelFactory.create() } val notificationsPlaceholderViewModel = rememberViewModel("QuickSettingsScene-notifPlaceholderViewModel") { notificationsPlaceholderViewModelFactory.create() Loading @@ -165,7 +144,6 @@ constructor( notificationStackScrollView = notificationStackScrollView.get(), viewModel = viewModel, headerViewModel = viewModel.qsContainerViewModel.shadeHeaderViewModel, brightnessMirrorViewModel = brightnessMirrorViewModel, notificationsPlaceholderViewModel = notificationsPlaceholderViewModel, mediaCarouselController = mediaCarouselController, mediaHost = mediaHost, Loading @@ -187,7 +165,6 @@ private fun ContentScope.QuickSettingsScene( notificationStackScrollView: NotificationScrollView, viewModel: QuickSettingsSceneContentViewModel, headerViewModel: ShadeHeaderViewModel, brightnessMirrorViewModel: BrightnessMirrorViewModel, notificationsPlaceholderViewModel: NotificationsPlaceholderViewModel, mediaCarouselController: MediaCarouselController, mediaHost: MediaHost, Loading @@ -196,7 +173,8 @@ private fun ContentScope.QuickSettingsScene( jankMonitor: InteractionJankMonitor, ) { val cutoutLocation = LocalDisplayCutout.current().location val brightnessMirrorShowing by brightnessMirrorViewModel.isShowing.collectAsStateWithLifecycle() val brightnessMirrorShowing = viewModel.qsContainerViewModel.brightnessSliderViewModel.showMirror val contentAlpha by animateFloatAsState( targetValue = if (brightnessMirrorShowing) 0f else 1f, Loading Loading @@ -229,15 +207,8 @@ private fun ContentScope.QuickSettingsScene( .thenIf(cutoutLocation != CutoutLocation.CENTER) { Modifier.displayCutoutPadding() } ) { val density = LocalDensity.current val isCustomizing by viewModel.qsSceneAdapter.isCustomizing.collectAsStateWithLifecycle() val isCustomizerShowing by viewModel.qsSceneAdapter.isCustomizerShowing.collectAsStateWithLifecycle() val customizingAnimationDuration by viewModel.qsSceneAdapter.customizerAnimationDuration.collectAsStateWithLifecycle() val screenHeight = with(density) { LocalConfiguration.current.screenHeightDp.dp.toPx() } BackHandler(enabled = isCustomizing) { viewModel.qsSceneAdapter.requestCloseCustomizer() } val lifecycleOwner = LocalLifecycleOwner.current val footerActionsViewModel = remember(lifecycleOwner, viewModel) { Loading @@ -256,34 +227,10 @@ private fun ContentScope.QuickSettingsScene( is TransitionState.Transition -> state.fromContent == Scenes.QuickSettings } LaunchedEffect(isCustomizing, scrollState) { if (isCustomizing) { scrollState.scrollTo(0) } } // ############# NAV BAR paddings ############### val navBarBottomHeight = WindowInsets.navigationBars.asPaddingValues().calculateBottomPadding() val bottomPadding by animateDpAsState( targetValue = if (isCustomizing) 0.dp else navBarBottomHeight, animationSpec = tween(customizingAnimationDuration), label = "animateQSSceneBottomPaddingAsState", ) val topPadding by animateDpAsState( targetValue = if (isCustomizing) ShadeHeader.Dimensions.StatusBarHeight else 0.dp, animationSpec = tween(customizingAnimationDuration), label = "animateQSSceneTopPaddingAsState", ) LaunchedEffect(navBarBottomHeight, density) { with(density) { viewModel.qsSceneAdapter.applyBottomNavBarPadding(navBarBottomHeight.roundToPx()) } } // ############# Media ############### val isMediaVisible = viewModel.isMediaVisible Loading @@ -304,67 +251,31 @@ private fun ContentScope.QuickSettingsScene( modifier = Modifier.fillMaxSize() .overscroll(verticalOverscrollEffect) .padding( top = topPadding.coerceAtLeast(0.dp), bottom = bottomPadding.coerceAtLeast(0.dp), ), .padding(bottom = navBarBottomHeight.coerceAtLeast(0.dp)), ) { Box(modifier = Modifier.fillMaxSize().weight(1f)) { val shadeHeaderAndQuickSettingsModifier = if (isCustomizerShowing) { Modifier.fillMaxHeight().align(Alignment.TopCenter) } else { Column( modifier = Modifier.verticalScroll(scrollState, enabled = isScrollable) .clipScrollableContainer(Orientation.Horizontal) .fillMaxWidth() .wrapContentHeight(unbounded = true) .align(Alignment.TopCenter) } Column( modifier = shadeHeaderAndQuickSettingsModifier.sysuiResTag("expanded_qs_scroll_view") .sysuiResTag("expanded_qs_scroll_view") ) { when (LocalWindowSizeClass.current.widthSizeClass) { WindowWidthSizeClass.Compact -> AnimatedVisibility( visible = !isCustomizing, enter = expandVertically( animationSpec = tween(customizingAnimationDuration), expandFrom = Alignment.Top, ) + slideInVertically( animationSpec = tween(customizingAnimationDuration) ) + fadeIn(tween(customizingAnimationDuration)), exit = shrinkVertically( animationSpec = tween(customizingAnimationDuration), shrinkTowards = Alignment.Top, ) + slideOutVertically( animationSpec = tween(customizingAnimationDuration) ) + fadeOut(tween(customizingAnimationDuration)), ) { ExpandedShadeHeader( viewModel = headerViewModel, modifier = Modifier.padding(horizontal = 16.dp), ) } else -> CollapsedShadeHeader(viewModel = headerViewModel, isSplitShade = false) } Spacer(modifier = Modifier.height(16.dp)) Column( modifier = Modifier.element(ElementKeys.QuickSettingsContent) .padding( horizontal = dimensionResource(id = R.dimen.qs_horizontal_margin) ) ) { QuickSettingsPanelLayout( brightness = @Composable { BrightnessSliderContainer( viewModel.qsContainerViewModel.brightnessSliderViewModel, containerColors = Loading @@ -375,56 +286,51 @@ private fun ContentScope.QuickSettingsScene( modifier = Modifier.padding( vertical = dimensionResource(id = R.dimen.qs_brightness_margin_top) dimensionResource( id = R.dimen.qs_brightness_margin_top ) ), ) }, tiles = @Composable { Box { GridAnchor() // This view has its own horizontal padding val content: @Composable () -> Unit = { TileGrid( viewModel.qsContainerViewModel.tileGridViewModel, modifier = Modifier.sysuiResTag("quick_settings_panel") .layoutId(QSMediaMeasurePolicy.LayoutId.QS), ) TileGrid(viewModel.qsContainerViewModel.tileGridViewModel) } }, media = @Composable { MediaCarousel( isVisible = isMediaVisible, mediaHost = mediaHost, modifier = Modifier.fillMaxWidth() .layoutId(QSMediaMeasurePolicy.LayoutId.Media) .padding( horizontal = dimensionResource(id = R.dimen.qs_horizontal_margin) dimensionResource( id = R.dimen.qs_horizontal_margin ) ), carouselController = mediaCarouselController, ) } val landscapeQsMediaMeasurePolicy = remember { QSMediaMeasurePolicy( { viewModel.qsSceneAdapter.qsHeight }, { mediaOffset.roundToPx() }, }, mediaInRow = mediaInRow, modifier = Modifier.element(ElementKeys.QuickSettingsContent) .padding( horizontal = dimensionResource(id = R.dimen.qs_horizontal_margin) ) } Column(modifier = Modifier.padding(horizontal = shadeHorizontalPadding)) { if (mediaInRow) { Layout( content = content, measurePolicy = landscapeQsMediaMeasurePolicy, .sysuiResTag("quick_settings_panel"), ) } else { content() } } } } } FooterActionsWithAnimatedVisibility( viewModel = footerActionsViewModel, isCustomizing = isCustomizing, customizingAnimationDuration = customizingAnimationDuration, isCustomizing = false, customizingAnimationDuration = 0, lifecycleOwner = lifecycleOwner, modifier = Modifier.align(Alignment.CenterHorizontally) Loading packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneContentViewModelTest.kt +0 −3 Original line number Diff line number Diff line Loading @@ -37,7 +37,6 @@ import com.android.systemui.scene.domain.interactor.sceneInteractor import com.android.systemui.scene.domain.startable.sceneContainerStartable import com.android.systemui.scene.shared.model.Overlays import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.settings.brightness.ui.viewmodel.brightnessMirrorViewModelFactory import com.android.systemui.shade.domain.interactor.disableDualShade import com.android.systemui.shade.domain.interactor.enableDualShade import com.android.systemui.shade.domain.interactor.enableSingleShade Loading Loading @@ -78,9 +77,7 @@ class QuickSettingsSceneContentViewModelTest : SysuiTestCase() { } underTest = QuickSettingsSceneContentViewModel( brightnessMirrorViewModelFactory = brightnessMirrorViewModelFactory, shadeHeaderViewModelFactory = shadeHeaderViewModelFactory, qsSceneAdapter = fakeQsSceneAdapter, qsContainerViewModelFactory = kosmos.quickSettingsContainerViewModelFactory, footerActionsViewModelFactory = footerActionsViewModelFactory, footerActionsController = footerActionsController, Loading packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneContentViewModel.kt +0 −4 Original line number Diff line number Diff line Loading @@ -25,12 +25,10 @@ import com.android.systemui.lifecycle.Hydrator import com.android.systemui.media.controls.domain.pipeline.interactor.MediaCarouselInteractor import com.android.systemui.qs.FooterActionsController import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsViewModel import com.android.systemui.qs.ui.adapter.QSSceneAdapter import com.android.systemui.scene.domain.interactor.SceneInteractor import com.android.systemui.scene.shared.model.Overlays import com.android.systemui.scene.shared.model.SceneFamilies import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.settings.brightness.ui.viewModel.BrightnessMirrorViewModel import com.android.systemui.shade.domain.interactor.ShadeModeInteractor import com.android.systemui.shade.shared.model.ShadeMode import com.android.systemui.shade.ui.viewmodel.ShadeHeaderViewModel Loading @@ -53,9 +51,7 @@ import kotlinx.coroutines.flow.onEach class QuickSettingsSceneContentViewModel @AssistedInject constructor( val brightnessMirrorViewModelFactory: BrightnessMirrorViewModel.Factory, val shadeHeaderViewModelFactory: ShadeHeaderViewModel.Factory, val qsSceneAdapter: QSSceneAdapter, qsContainerViewModelFactory: QuickSettingsContainerViewModel.Factory, private val footerActionsViewModelFactory: FooterActionsViewModel.Factory, private val footerActionsController: FooterActionsController, Loading packages/SystemUI/tests/utils/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneContentViewModelKosmos.kt +2 −25 Original line number Diff line number Diff line Loading @@ -16,42 +16,19 @@ package com.android.systemui.qs.ui.viewmodel import android.view.View import android.view.ViewGroup import android.widget.FrameLayout import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture import com.android.systemui.kosmos.testDispatcher import com.android.systemui.media.controls.domain.pipeline.interactor.mediaCarouselInteractor import com.android.systemui.qs.footerActionsController import com.android.systemui.qs.footerActionsViewModelFactory import com.android.systemui.qs.ui.adapter.FakeQSSceneAdapter import com.android.systemui.settings.brightness.ui.viewmodel.brightnessMirrorViewModelFactory import com.android.systemui.shade.ui.viewmodel.shadeHeaderViewModelFactory import com.android.systemui.shade.domain.interactor.shadeModeInteractor import com.android.systemui.scene.domain.interactor.sceneInteractor import org.mockito.kotlin.doReturn import org.mockito.kotlin.mock import org.mockito.kotlin.stub import com.android.systemui.shade.domain.interactor.shadeModeInteractor import com.android.systemui.shade.ui.viewmodel.shadeHeaderViewModelFactory val Kosmos.quickSettingsSceneContentViewModel by Fixture { QuickSettingsSceneContentViewModel( brightnessMirrorViewModelFactory = brightnessMirrorViewModelFactory, shadeHeaderViewModelFactory = shadeHeaderViewModelFactory, qsSceneAdapter = FakeQSSceneAdapter({ // The Quick Settings content installs this view as a child of FrameLayout so its layout // params are required. val view = mock<View>() view.stub { on { layoutParams } doReturn FrameLayout.LayoutParams( ViewGroup.MarginLayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, ) ) } view }), qsContainerViewModelFactory = quickSettingsContainerViewModelFactory, footerActionsViewModelFactory = footerActionsViewModelFactory, footerActionsController = footerActionsController, Loading Loading
packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsPanelLayout.kt 0 → 100644 +61 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.systemui.qs.ui.composable import androidx.compose.foundation.layout.Arrangement.spacedBy import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @Composable fun QuickSettingsPanelLayout( brightness: @Composable () -> Unit, tiles: @Composable () -> Unit, media: @Composable () -> Unit, mediaInRow: Boolean, modifier: Modifier = Modifier, ) { if (mediaInRow) { Column( verticalArrangement = spacedBy(QuickSettingsShade.Dimensions.Padding), horizontalAlignment = Alignment.CenterHorizontally, modifier = modifier, ) { brightness() Row( horizontalArrangement = spacedBy(QuickSettingsShade.Dimensions.Padding), verticalAlignment = Alignment.CenterVertically, ) { Box(modifier = Modifier.weight(1f)) { tiles() } Box(modifier = Modifier.weight(1f)) { media() } } } } else { Column( verticalArrangement = spacedBy(QuickSettingsShade.Dimensions.Padding), horizontalAlignment = Alignment.CenterHorizontally, modifier = modifier, ) { brightness() tiles() media() } } }
packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt +57 −151 Original line number Diff line number Diff line Loading @@ -16,17 +16,7 @@ package com.android.systemui.qs.ui.composable import androidx.activity.compose.BackHandler import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.core.animateDpAsState import androidx.compose.animation.core.animateFloatAsState import androidx.compose.animation.core.tween import androidx.compose.animation.expandVertically import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.animation.shrinkVertically import androidx.compose.animation.slideInVertically import androidx.compose.animation.slideOutVertically import androidx.compose.foundation.background import androidx.compose.foundation.clipScrollableContainer import androidx.compose.foundation.gestures.Orientation Loading @@ -36,7 +26,6 @@ import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.asPaddingValues import androidx.compose.foundation.layout.displayCutoutPadding import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height Loading @@ -51,7 +40,6 @@ import androidx.compose.foundation.verticalScroll import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.ui.Alignment Loading @@ -59,8 +47,6 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.CompositingStrategy import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.layout.Layout import androidx.compose.ui.layout.layoutId import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalLifecycleOwner Loading @@ -68,7 +54,6 @@ import androidx.compose.ui.res.colorResource import androidx.compose.ui.res.dimensionResource import androidx.compose.ui.unit.IntOffset import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.android.compose.animation.scene.ContentScope import com.android.compose.animation.scene.UserAction import com.android.compose.animation.scene.UserActionResult Loading Loading @@ -107,11 +92,9 @@ import com.android.systemui.res.R import com.android.systemui.scene.session.ui.composable.SaveableSession import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.scene.ui.composable.Scene import com.android.systemui.settings.brightness.ui.viewModel.BrightnessMirrorViewModel import com.android.systemui.shade.ui.composable.CollapsedShadeHeader import com.android.systemui.shade.ui.composable.ExpandedShadeHeader import com.android.systemui.shade.ui.composable.Shade import com.android.systemui.shade.ui.composable.ShadeHeader import com.android.systemui.shade.ui.viewmodel.ShadeHeaderViewModel import com.android.systemui.statusbar.notification.stack.ui.view.NotificationScrollView import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationsPlaceholderViewModel Loading Loading @@ -153,10 +136,6 @@ constructor( override fun ContentScope.Content(modifier: Modifier) { val viewModel = rememberViewModel("QuickSettingsScene-viewModel") { contentViewModelFactory.create() } val brightnessMirrorViewModel = rememberViewModel("QuickSettingsScene-brightnessMirrorViewModel") { viewModel.brightnessMirrorViewModelFactory.create() } val notificationsPlaceholderViewModel = rememberViewModel("QuickSettingsScene-notifPlaceholderViewModel") { notificationsPlaceholderViewModelFactory.create() Loading @@ -165,7 +144,6 @@ constructor( notificationStackScrollView = notificationStackScrollView.get(), viewModel = viewModel, headerViewModel = viewModel.qsContainerViewModel.shadeHeaderViewModel, brightnessMirrorViewModel = brightnessMirrorViewModel, notificationsPlaceholderViewModel = notificationsPlaceholderViewModel, mediaCarouselController = mediaCarouselController, mediaHost = mediaHost, Loading @@ -187,7 +165,6 @@ private fun ContentScope.QuickSettingsScene( notificationStackScrollView: NotificationScrollView, viewModel: QuickSettingsSceneContentViewModel, headerViewModel: ShadeHeaderViewModel, brightnessMirrorViewModel: BrightnessMirrorViewModel, notificationsPlaceholderViewModel: NotificationsPlaceholderViewModel, mediaCarouselController: MediaCarouselController, mediaHost: MediaHost, Loading @@ -196,7 +173,8 @@ private fun ContentScope.QuickSettingsScene( jankMonitor: InteractionJankMonitor, ) { val cutoutLocation = LocalDisplayCutout.current().location val brightnessMirrorShowing by brightnessMirrorViewModel.isShowing.collectAsStateWithLifecycle() val brightnessMirrorShowing = viewModel.qsContainerViewModel.brightnessSliderViewModel.showMirror val contentAlpha by animateFloatAsState( targetValue = if (brightnessMirrorShowing) 0f else 1f, Loading Loading @@ -229,15 +207,8 @@ private fun ContentScope.QuickSettingsScene( .thenIf(cutoutLocation != CutoutLocation.CENTER) { Modifier.displayCutoutPadding() } ) { val density = LocalDensity.current val isCustomizing by viewModel.qsSceneAdapter.isCustomizing.collectAsStateWithLifecycle() val isCustomizerShowing by viewModel.qsSceneAdapter.isCustomizerShowing.collectAsStateWithLifecycle() val customizingAnimationDuration by viewModel.qsSceneAdapter.customizerAnimationDuration.collectAsStateWithLifecycle() val screenHeight = with(density) { LocalConfiguration.current.screenHeightDp.dp.toPx() } BackHandler(enabled = isCustomizing) { viewModel.qsSceneAdapter.requestCloseCustomizer() } val lifecycleOwner = LocalLifecycleOwner.current val footerActionsViewModel = remember(lifecycleOwner, viewModel) { Loading @@ -256,34 +227,10 @@ private fun ContentScope.QuickSettingsScene( is TransitionState.Transition -> state.fromContent == Scenes.QuickSettings } LaunchedEffect(isCustomizing, scrollState) { if (isCustomizing) { scrollState.scrollTo(0) } } // ############# NAV BAR paddings ############### val navBarBottomHeight = WindowInsets.navigationBars.asPaddingValues().calculateBottomPadding() val bottomPadding by animateDpAsState( targetValue = if (isCustomizing) 0.dp else navBarBottomHeight, animationSpec = tween(customizingAnimationDuration), label = "animateQSSceneBottomPaddingAsState", ) val topPadding by animateDpAsState( targetValue = if (isCustomizing) ShadeHeader.Dimensions.StatusBarHeight else 0.dp, animationSpec = tween(customizingAnimationDuration), label = "animateQSSceneTopPaddingAsState", ) LaunchedEffect(navBarBottomHeight, density) { with(density) { viewModel.qsSceneAdapter.applyBottomNavBarPadding(navBarBottomHeight.roundToPx()) } } // ############# Media ############### val isMediaVisible = viewModel.isMediaVisible Loading @@ -304,67 +251,31 @@ private fun ContentScope.QuickSettingsScene( modifier = Modifier.fillMaxSize() .overscroll(verticalOverscrollEffect) .padding( top = topPadding.coerceAtLeast(0.dp), bottom = bottomPadding.coerceAtLeast(0.dp), ), .padding(bottom = navBarBottomHeight.coerceAtLeast(0.dp)), ) { Box(modifier = Modifier.fillMaxSize().weight(1f)) { val shadeHeaderAndQuickSettingsModifier = if (isCustomizerShowing) { Modifier.fillMaxHeight().align(Alignment.TopCenter) } else { Column( modifier = Modifier.verticalScroll(scrollState, enabled = isScrollable) .clipScrollableContainer(Orientation.Horizontal) .fillMaxWidth() .wrapContentHeight(unbounded = true) .align(Alignment.TopCenter) } Column( modifier = shadeHeaderAndQuickSettingsModifier.sysuiResTag("expanded_qs_scroll_view") .sysuiResTag("expanded_qs_scroll_view") ) { when (LocalWindowSizeClass.current.widthSizeClass) { WindowWidthSizeClass.Compact -> AnimatedVisibility( visible = !isCustomizing, enter = expandVertically( animationSpec = tween(customizingAnimationDuration), expandFrom = Alignment.Top, ) + slideInVertically( animationSpec = tween(customizingAnimationDuration) ) + fadeIn(tween(customizingAnimationDuration)), exit = shrinkVertically( animationSpec = tween(customizingAnimationDuration), shrinkTowards = Alignment.Top, ) + slideOutVertically( animationSpec = tween(customizingAnimationDuration) ) + fadeOut(tween(customizingAnimationDuration)), ) { ExpandedShadeHeader( viewModel = headerViewModel, modifier = Modifier.padding(horizontal = 16.dp), ) } else -> CollapsedShadeHeader(viewModel = headerViewModel, isSplitShade = false) } Spacer(modifier = Modifier.height(16.dp)) Column( modifier = Modifier.element(ElementKeys.QuickSettingsContent) .padding( horizontal = dimensionResource(id = R.dimen.qs_horizontal_margin) ) ) { QuickSettingsPanelLayout( brightness = @Composable { BrightnessSliderContainer( viewModel.qsContainerViewModel.brightnessSliderViewModel, containerColors = Loading @@ -375,56 +286,51 @@ private fun ContentScope.QuickSettingsScene( modifier = Modifier.padding( vertical = dimensionResource(id = R.dimen.qs_brightness_margin_top) dimensionResource( id = R.dimen.qs_brightness_margin_top ) ), ) }, tiles = @Composable { Box { GridAnchor() // This view has its own horizontal padding val content: @Composable () -> Unit = { TileGrid( viewModel.qsContainerViewModel.tileGridViewModel, modifier = Modifier.sysuiResTag("quick_settings_panel") .layoutId(QSMediaMeasurePolicy.LayoutId.QS), ) TileGrid(viewModel.qsContainerViewModel.tileGridViewModel) } }, media = @Composable { MediaCarousel( isVisible = isMediaVisible, mediaHost = mediaHost, modifier = Modifier.fillMaxWidth() .layoutId(QSMediaMeasurePolicy.LayoutId.Media) .padding( horizontal = dimensionResource(id = R.dimen.qs_horizontal_margin) dimensionResource( id = R.dimen.qs_horizontal_margin ) ), carouselController = mediaCarouselController, ) } val landscapeQsMediaMeasurePolicy = remember { QSMediaMeasurePolicy( { viewModel.qsSceneAdapter.qsHeight }, { mediaOffset.roundToPx() }, }, mediaInRow = mediaInRow, modifier = Modifier.element(ElementKeys.QuickSettingsContent) .padding( horizontal = dimensionResource(id = R.dimen.qs_horizontal_margin) ) } Column(modifier = Modifier.padding(horizontal = shadeHorizontalPadding)) { if (mediaInRow) { Layout( content = content, measurePolicy = landscapeQsMediaMeasurePolicy, .sysuiResTag("quick_settings_panel"), ) } else { content() } } } } } FooterActionsWithAnimatedVisibility( viewModel = footerActionsViewModel, isCustomizing = isCustomizing, customizingAnimationDuration = customizingAnimationDuration, isCustomizing = false, customizingAnimationDuration = 0, lifecycleOwner = lifecycleOwner, modifier = Modifier.align(Alignment.CenterHorizontally) Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneContentViewModelTest.kt +0 −3 Original line number Diff line number Diff line Loading @@ -37,7 +37,6 @@ import com.android.systemui.scene.domain.interactor.sceneInteractor import com.android.systemui.scene.domain.startable.sceneContainerStartable import com.android.systemui.scene.shared.model.Overlays import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.settings.brightness.ui.viewmodel.brightnessMirrorViewModelFactory import com.android.systemui.shade.domain.interactor.disableDualShade import com.android.systemui.shade.domain.interactor.enableDualShade import com.android.systemui.shade.domain.interactor.enableSingleShade Loading Loading @@ -78,9 +77,7 @@ class QuickSettingsSceneContentViewModelTest : SysuiTestCase() { } underTest = QuickSettingsSceneContentViewModel( brightnessMirrorViewModelFactory = brightnessMirrorViewModelFactory, shadeHeaderViewModelFactory = shadeHeaderViewModelFactory, qsSceneAdapter = fakeQsSceneAdapter, qsContainerViewModelFactory = kosmos.quickSettingsContainerViewModelFactory, footerActionsViewModelFactory = footerActionsViewModelFactory, footerActionsController = footerActionsController, Loading
packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneContentViewModel.kt +0 −4 Original line number Diff line number Diff line Loading @@ -25,12 +25,10 @@ import com.android.systemui.lifecycle.Hydrator import com.android.systemui.media.controls.domain.pipeline.interactor.MediaCarouselInteractor import com.android.systemui.qs.FooterActionsController import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsViewModel import com.android.systemui.qs.ui.adapter.QSSceneAdapter import com.android.systemui.scene.domain.interactor.SceneInteractor import com.android.systemui.scene.shared.model.Overlays import com.android.systemui.scene.shared.model.SceneFamilies import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.settings.brightness.ui.viewModel.BrightnessMirrorViewModel import com.android.systemui.shade.domain.interactor.ShadeModeInteractor import com.android.systemui.shade.shared.model.ShadeMode import com.android.systemui.shade.ui.viewmodel.ShadeHeaderViewModel Loading @@ -53,9 +51,7 @@ import kotlinx.coroutines.flow.onEach class QuickSettingsSceneContentViewModel @AssistedInject constructor( val brightnessMirrorViewModelFactory: BrightnessMirrorViewModel.Factory, val shadeHeaderViewModelFactory: ShadeHeaderViewModel.Factory, val qsSceneAdapter: QSSceneAdapter, qsContainerViewModelFactory: QuickSettingsContainerViewModel.Factory, private val footerActionsViewModelFactory: FooterActionsViewModel.Factory, private val footerActionsController: FooterActionsController, Loading
packages/SystemUI/tests/utils/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneContentViewModelKosmos.kt +2 −25 Original line number Diff line number Diff line Loading @@ -16,42 +16,19 @@ package com.android.systemui.qs.ui.viewmodel import android.view.View import android.view.ViewGroup import android.widget.FrameLayout import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture import com.android.systemui.kosmos.testDispatcher import com.android.systemui.media.controls.domain.pipeline.interactor.mediaCarouselInteractor import com.android.systemui.qs.footerActionsController import com.android.systemui.qs.footerActionsViewModelFactory import com.android.systemui.qs.ui.adapter.FakeQSSceneAdapter import com.android.systemui.settings.brightness.ui.viewmodel.brightnessMirrorViewModelFactory import com.android.systemui.shade.ui.viewmodel.shadeHeaderViewModelFactory import com.android.systemui.shade.domain.interactor.shadeModeInteractor import com.android.systemui.scene.domain.interactor.sceneInteractor import org.mockito.kotlin.doReturn import org.mockito.kotlin.mock import org.mockito.kotlin.stub import com.android.systemui.shade.domain.interactor.shadeModeInteractor import com.android.systemui.shade.ui.viewmodel.shadeHeaderViewModelFactory val Kosmos.quickSettingsSceneContentViewModel by Fixture { QuickSettingsSceneContentViewModel( brightnessMirrorViewModelFactory = brightnessMirrorViewModelFactory, shadeHeaderViewModelFactory = shadeHeaderViewModelFactory, qsSceneAdapter = FakeQSSceneAdapter({ // The Quick Settings content installs this view as a child of FrameLayout so its layout // params are required. val view = mock<View>() view.stub { on { layoutParams } doReturn FrameLayout.LayoutParams( ViewGroup.MarginLayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, ) ) } view }), qsContainerViewModelFactory = quickSettingsContainerViewModelFactory, footerActionsViewModelFactory = footerActionsViewModelFactory, footerActionsController = footerActionsController, Loading