From 828dd91d49bf390026f5a4f12806f221f7da83af Mon Sep 17 00:00:00 2001 From: Fabián Kozynski Date: Fri, 21 Jun 2024 16:22:53 -0400 Subject: [Flexiglass] Fix brightness mirror The brightness mirror was not properly aligned after changes for focus. Replicate BrightnessMirrorController so things match. We also need to make sure that the mirror container can be wider than its container in flexiglass. Also, have two different ways of calculating offset based on the location of the mirror with respect to the window. Test: atest com.android.systemui.settings.brightness.ui Test: manual in phone, unfolded, and landscape Fixes: 348640465 Flag: com.android.systemui.scene_container Change-Id: Ic0c500e1dc2258e8b1cb368b8aa42b9ad183ce65 --- .../systemui/qs/ui/composable/BrightnessMirror.kt | 21 +++++++-- .../qs/ui/composable/QuickSettingsScene.kt | 6 ++- .../systemui/shade/ui/composable/ShadeScene.kt | 7 ++- .../ui/binder/BrightnessMirrorInflaterTest.kt | 23 +++++++++ .../ui/viewmodel/BrightnessMirrorViewModelTest.kt | 55 ++++++++-------------- .../ui/binder/BrightnessMirrorInflater.kt | 11 ++++- .../ui/viewModel/BrightnessMirrorViewModel.kt | 27 +++++++++-- 7 files changed, 103 insertions(+), 47 deletions(-) diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/BrightnessMirror.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/BrightnessMirror.kt index 73a624a030fe..aca473d8eabc 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/BrightnessMirror.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/BrightnessMirror.kt @@ -18,8 +18,9 @@ package com.android.systemui.qs.ui.composable import androidx.compose.animation.core.animateFloatAsState import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.offset +import androidx.compose.foundation.layout.wrapContentWidth import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment @@ -39,6 +40,7 @@ fun BrightnessMirror( viewModel: BrightnessMirrorViewModel, qsSceneAdapter: QSSceneAdapter, modifier: Modifier = Modifier, + measureFromContainer: Boolean = false, ) { val isShowing by viewModel.isShowing.collectAsStateWithLifecycle() val mirrorAlpha by @@ -47,9 +49,22 @@ fun BrightnessMirror( label = "alphaAnimationBrightnessMirrorShowing", ) val mirrorOffsetAndSize by viewModel.locationAndSize.collectAsStateWithLifecycle() - val offset = IntOffset(0, mirrorOffsetAndSize.yOffset) + val yOffset = + if (measureFromContainer) { + mirrorOffsetAndSize.yOffsetFromContainer + } else { + mirrorOffsetAndSize.yOffsetFromWindow + } + val offset = IntOffset(0, yOffset) - Box(modifier = modifier.fillMaxSize().graphicsLayer { alpha = mirrorAlpha }) { + // Use unbounded=true as the full mirror (with paddings and background offset) may be larger + // than the space we have (but it will fit, because the brightness slider fits). + Box( + modifier = + modifier.fillMaxHeight().wrapContentWidth(unbounded = true).graphicsLayer { + alpha = mirrorAlpha + } + ) { QuickSettingsTheme { // The assumption for using this AndroidView is that there will be only one in view at // a given time (which is a reasonable assumption). Because `QSSceneAdapter` (actually diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt index 0b57151e971d..2d5d25913074 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt @@ -185,7 +185,11 @@ private fun SceneScope.QuickSettingsScene( BrightnessMirror( viewModel = viewModel.brightnessMirrorViewModel, - qsSceneAdapter = viewModel.qsSceneAdapter + qsSceneAdapter = viewModel.qsSceneAdapter, + modifier = + Modifier.thenIf(cutoutLocation != CutoutLocation.CENTER) { + Modifier.displayCutoutPadding() + } ) val shouldPunchHoleBehindScrim = diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt index edef5fb2760a..3d6362eb1b62 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt @@ -36,7 +36,6 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.navigationBars import androidx.compose.foundation.layout.navigationBarsPadding -import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.padding import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.RoundedCornerShape @@ -474,9 +473,9 @@ private fun SceneScope.SplitShade( BrightnessMirror( viewModel = viewModel.brightnessMirrorViewModel, qsSceneAdapter = viewModel.qsSceneAdapter, - // Need to remove the offset of the header height, as the mirror uses - // the position of the Brightness slider in the window - modifier = Modifier.offset(y = -ShadeHeader.Dimensions.CollapsedHeight) + // Need to use the offset measured from the container as the header + // has to be accounted for + measureFromContainer = true ) Column( verticalArrangement = Arrangement.Top, diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/settings/brightness/ui/binder/BrightnessMirrorInflaterTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/settings/brightness/ui/binder/BrightnessMirrorInflaterTest.kt index 6de7f403a745..13b61bcae6ce 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/settings/brightness/ui/binder/BrightnessMirrorInflaterTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/settings/brightness/ui/binder/BrightnessMirrorInflaterTest.kt @@ -68,4 +68,27 @@ class BrightnessMirrorInflaterTest : SysuiTestCase() { Assert.setTestThread(null) } + + @Test + fun inflate_frameHasPadding() { + Assert.setTestThread(Thread.currentThread()) + + val (frame, _) = + BrightnessMirrorInflater.inflate( + themedContext, + kosmos.brightnessSliderControllerFactory, + ) + + assertThat(frame.visibility).isEqualTo(View.VISIBLE) + + val padding = + context.resources.getDimensionPixelSize(R.dimen.rounded_slider_background_padding) + + assertThat(frame.paddingLeft).isEqualTo(padding) + assertThat(frame.paddingTop).isEqualTo(padding) + assertThat(frame.paddingRight).isEqualTo(padding) + assertThat(frame.paddingBottom).isEqualTo(padding) + + Assert.setTestThread(null) + } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/settings/brightness/ui/viewmodel/BrightnessMirrorViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/settings/brightness/ui/viewmodel/BrightnessMirrorViewModelTest.kt index 09fc6f9ad96d..90c11d466f80 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/settings/brightness/ui/viewmodel/BrightnessMirrorViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/settings/brightness/ui/viewmodel/BrightnessMirrorViewModelTest.kt @@ -16,10 +16,9 @@ package com.android.systemui.settings.brightness.ui.viewmodel -import android.content.applicationContext import android.content.res.mainResources -import android.view.ContextThemeWrapper import android.view.View +import android.widget.FrameLayout import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase @@ -27,12 +26,10 @@ import com.android.systemui.coroutines.collectLastValue import com.android.systemui.kosmos.testScope import com.android.systemui.res.R import com.android.systemui.settings.brightness.domain.interactor.brightnessMirrorShowingInteractor -import com.android.systemui.settings.brightness.ui.binder.BrightnessMirrorInflater import com.android.systemui.settings.brightness.ui.viewModel.BrightnessMirrorViewModel import com.android.systemui.settings.brightness.ui.viewModel.LocationAndSize import com.android.systemui.settings.brightnessSliderControllerFactory import com.android.systemui.testKosmos -import com.android.systemui.util.Assert import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever @@ -47,9 +44,6 @@ class BrightnessMirrorViewModelTest : SysuiTestCase() { private val kosmos = testKosmos() - private val themedContext = - ContextThemeWrapper(kosmos.applicationContext, R.style.Theme_SystemUI_QuickSettings) - private val underTest = with(kosmos) { BrightnessMirrorViewModel( @@ -76,7 +70,7 @@ class BrightnessMirrorViewModelTest : SysuiTestCase() { } @Test - fun setLocationInWindow_correctLocationAndSize() = + fun locationInWindowAndContainer_correctLocationAndSize() = with(kosmos) { testScope.runTest { val locationAndSize by collectLastValue(underTest.locationAndSize) @@ -101,6 +95,7 @@ class BrightnessMirrorViewModelTest : SysuiTestCase() { whenever(measuredHeight).thenReturn(height) whenever(measuredWidth).thenReturn(width) } + val yOffsetFromContainer = setContainerViewHierarchy(mockView) underTest.setLocationAndSize(mockView) @@ -108,7 +103,8 @@ class BrightnessMirrorViewModelTest : SysuiTestCase() { .isEqualTo( // Adjust for padding around the view LocationAndSize( - yOffset = y - padding, + yOffsetFromWindow = y - padding, + yOffsetFromContainer = yOffsetFromContainer - padding, width = width + 2 * padding, height = height + 2 * padding, ) @@ -116,31 +112,20 @@ class BrightnessMirrorViewModelTest : SysuiTestCase() { } } - @Test - fun setLocationInWindow_paddingSetToRootView() = - with(kosmos) { - Assert.setTestThread(Thread.currentThread()) - val padding = - mainResources.getDimensionPixelSize(R.dimen.rounded_slider_background_padding) - - val view = mock() - - val (_, sliderController) = - BrightnessMirrorInflater.inflate( - themedContext, - brightnessSliderControllerFactory, - ) - underTest.setToggleSlider(sliderController) - - underTest.setLocationAndSize(view) - - with(sliderController.rootView) { - assertThat(paddingBottom).isEqualTo(padding) - assertThat(paddingTop).isEqualTo(padding) - assertThat(paddingLeft).isEqualTo(padding) - assertThat(paddingRight).isEqualTo(padding) - } + private fun setContainerViewHierarchy(mockView: View): Int { + val rootView = FrameLayout(context) + val containerView = FrameLayout(context).apply { id = R.id.quick_settings_container } + val otherView = FrameLayout(context) - Assert.setTestThread(null) - } + rootView.addView(containerView) + containerView.addView(otherView) + otherView.addView(mockView) + + containerView.setLeftTopRightBottom(1, /* top= */ 1, 1, 1) + otherView.setLeftTopRightBottom(0, /* top= */ 2, 0, 0) + whenever(mockView.parent).thenReturn(otherView) + whenever(mockView.top).thenReturn(3) + + return 2 + 3 + } } diff --git a/packages/SystemUI/src/com/android/systemui/settings/brightness/ui/binder/BrightnessMirrorInflater.kt b/packages/SystemUI/src/com/android/systemui/settings/brightness/ui/binder/BrightnessMirrorInflater.kt index 468a87325507..cebc59bdd94b 100644 --- a/packages/SystemUI/src/com/android/systemui/settings/brightness/ui/binder/BrightnessMirrorInflater.kt +++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/ui/binder/BrightnessMirrorInflater.kt @@ -21,6 +21,7 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.core.view.isVisible +import androidx.core.view.setPadding import com.android.systemui.res.R import com.android.systemui.settings.brightness.BrightnessSliderController @@ -33,7 +34,15 @@ object BrightnessMirrorInflater { val frame = (LayoutInflater.from(context).inflate(R.layout.brightness_mirror_container, null) as ViewGroup) - .apply { isVisible = true } + .apply { + isVisible = true + // Match BrightnessMirrorController padding + setPadding( + context.resources.getDimensionPixelSize( + R.dimen.rounded_slider_background_padding + ) + ) + } val sliderController = sliderControllerFactory.create(context, frame) sliderController.init() frame.addView( diff --git a/packages/SystemUI/src/com/android/systemui/settings/brightness/ui/viewModel/BrightnessMirrorViewModel.kt b/packages/SystemUI/src/com/android/systemui/settings/brightness/ui/viewModel/BrightnessMirrorViewModel.kt index 2651a994bb55..79e8b879288e 100644 --- a/packages/SystemUI/src/com/android/systemui/settings/brightness/ui/viewModel/BrightnessMirrorViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/ui/viewModel/BrightnessMirrorViewModel.kt @@ -17,6 +17,7 @@ package com.android.systemui.settings.brightness.ui.viewModel import android.content.res.Resources +import android.util.Log import android.view.View import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Main @@ -67,25 +68,45 @@ constructor( override fun setLocationAndSize(view: View) { view.getLocationInWindow(tempPosition) val padding = resources.getDimensionPixelSize(R.dimen.rounded_slider_background_padding) - _toggleSlider?.rootView?.setPadding(padding, padding, padding, padding) // Account for desired padding _locationAndSize.value = LocationAndSize( - yOffset = tempPosition[1] - padding, + yOffsetFromContainer = view.findTopFromContainer() - padding, + yOffsetFromWindow = tempPosition[1] - padding, width = view.measuredWidth + 2 * padding, height = view.measuredHeight + 2 * padding, ) } + private fun View.findTopFromContainer(): Int { + var out = 0 + var view = this + while (view.id != R.id.quick_settings_container) { + out += view.top + val parent = view.parent as? View + if (parent == null) { + Log.wtf(TAG, "Couldn't find container in parents of $this") + break + } + view = parent + } + return out + } + // Callbacks are used for indicating reinflation when the config changes in some ways (like // density). However, we don't need that as we recompose the view anyway override fun addCallback(listener: MirrorController.BrightnessMirrorListener) {} override fun removeCallback(listener: MirrorController.BrightnessMirrorListener) {} + + companion object { + private const val TAG = "BrightnessMirrorViewModel" + } } data class LocationAndSize( - val yOffset: Int = 0, + val yOffsetFromContainer: Int = 0, + val yOffsetFromWindow: Int = 0, val width: Int = 0, val height: Int = 0, ) -- cgit v1.2.3-59-g8ed1b