Brightness dialog use new composable
Test: atest BrightnessDialogTest
Flag: com.android.systemui.qs_ui_refactor_compose_fragment
Fixes: 375193493
Change-Id: I6e2964a45c5b0b95ef33fa989cca8fd7dc992c2c
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index 9265ceb..e7ff81c 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -97,6 +97,7 @@
"tests/src/**/systemui/media/dialog/MediaOutputBroadcastDialogTest.java",
"tests/src/**/systemui/media/dialog/MediaOutputDialogTest.java",
"tests/src/**/systemui/mediaprojection/permission/MediaProjectionPermissionDialogDelegateTest.kt",
+ "tests/src/**/systemui/settings/brightness/BrightnessDialogTest.kt",
],
}
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index 20e70e0..88ed4e3 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -286,4 +286,6 @@
<item type="id" name="snapshot_view_binding" />
<item type="id" name="snapshot_view_binding_root" />
+ <item type="id" name="brightness_dialog_slider" />
+
</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessDialog.java b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessDialog.java
index a62edcb..8c004c4 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessDialog.java
@@ -39,10 +39,16 @@
import android.view.accessibility.AccessibilityManager;
import android.widget.FrameLayout;
+import androidx.annotation.NonNull;
+import androidx.compose.ui.platform.ComposeView;
+
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.systemui.brightness.ui.viewmodel.BrightnessSliderViewModel;
+import com.android.systemui.compose.ComposeInitializer;
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.qs.flags.QSComposeFragment;
import com.android.systemui.res.R;
import com.android.systemui.shade.domain.interactor.ShadeInteractor;
import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
@@ -65,6 +71,7 @@
private final AccessibilityManagerWrapper mAccessibilityMgr;
private Runnable mCancelTimeoutRunnable;
private final ShadeInteractor mShadeInteractor;
+ private final BrightnessSliderViewModel.Factory mBrightnessSliderViewModelFactory;
@Inject
public BrightnessDialog(
@@ -72,13 +79,15 @@
BrightnessController.Factory brightnessControllerFactory,
@Main DelayableExecutor mainExecutor,
AccessibilityManagerWrapper accessibilityMgr,
- ShadeInteractor shadeInteractor
+ ShadeInteractor shadeInteractor,
+ BrightnessSliderViewModel.Factory brightnessSliderViewModelFactory
) {
mToggleSliderFactory = brightnessSliderfactory;
mBrightnessControllerFactory = brightnessControllerFactory;
mMainExecutor = mainExecutor;
mAccessibilityMgr = accessibilityMgr;
mShadeInteractor = shadeInteractor;
+ mBrightnessSliderViewModelFactory = brightnessSliderViewModelFactory;
}
@@ -86,14 +95,28 @@
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setWindowAttributes();
- setContentView(R.layout.brightness_mirror_container);
- setBrightnessDialogViewAttributes();
+ View view;
+ if (!QSComposeFragment.isEnabled()) {
+ setContentView(R.layout.brightness_mirror_container);
+ view = findViewById(R.id.brightness_mirror_container);
+ setDialogContent((FrameLayout) view);
+ } else {
+ ComposeView composeView = new ComposeView(this);
+ ComposeDialogComposableProvider.INSTANCE.setComposableBrightness(
+ composeView,
+ new ComposableProvider(mBrightnessSliderViewModelFactory)
+ );
+ composeView.setId(R.id.brightness_dialog_slider);
+ setContentView(composeView);
+ ((ViewGroup) composeView.getParent()).setClipChildren(false);
+ view = composeView;
+ }
+ setBrightnessDialogViewAttributes(view);
if (mShadeInteractor.isQsExpanded().getValue()) {
finish();
}
- View view = findViewById(R.id.brightness_mirror_container);
if (view != null) {
collectFlow(view, mShadeInteractor.isQsExpanded(), this::onShadeStateChange);
}
@@ -117,13 +140,27 @@
window.getDecorView();
window.setLayout(WRAP_CONTENT, WRAP_CONTENT);
getTheme().applyStyle(R.style.Theme_SystemUI_QuickSettings, false);
+ if (QSComposeFragment.isEnabled()) {
+ window.getDecorView().addOnAttachStateChangeListener(
+ new View.OnAttachStateChangeListener() {
+ @Override
+ public void onViewAttachedToWindow(@NonNull View v) {
+ ComposeInitializer.INSTANCE.onAttachedToWindow(v);
+ }
+
+ @Override
+ public void onViewDetachedFromWindow(@NonNull View v) {
+ ComposeInitializer.INSTANCE.onDetachedFromWindow(v);
+ }
+ });
+ }
}
- void setBrightnessDialogViewAttributes() {
- FrameLayout frame = findViewById(R.id.brightness_mirror_container);
+ void setBrightnessDialogViewAttributes(View container) {
// The brightness mirror container is INVISIBLE by default.
- frame.setVisibility(View.VISIBLE);
- ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) frame.getLayoutParams();
+ container.setVisibility(View.VISIBLE);
+ ViewGroup.MarginLayoutParams lp =
+ (ViewGroup.MarginLayoutParams) container.getLayoutParams();
int horizontalMargin =
getResources().getDimensionPixelSize(R.dimen.notification_side_paddings);
lp.leftMargin = horizontalMargin;
@@ -136,23 +173,6 @@
lp.topMargin = verticalMargin;
lp.bottomMargin = verticalMargin;
- frame.setLayoutParams(lp);
- Rect bounds = new Rect();
- frame.addOnLayoutChangeListener(
- (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
- // Exclude this view (and its horizontal margins) from triggering gestures.
- // This prevents back gesture from being triggered by dragging close to the
- // edge of the slider (0% or 100%).
- bounds.set(-horizontalMargin, 0, right - left + horizontalMargin, bottom - top);
- v.setSystemGestureExclusionRects(List.of(bounds));
- });
-
- BrightnessSliderController controller = mToggleSliderFactory.create(this, frame);
- controller.init();
- frame.addView(controller.getRootView(), MATCH_PARENT, WRAP_CONTENT);
-
- mBrightnessController = mBrightnessControllerFactory.create(controller);
-
Configuration configuration = getResources().getConfiguration();
int orientation = configuration.orientation;
int windowWidth = getWindowAvailableWidth();
@@ -165,7 +185,23 @@
lp.width = windowWidth - horizontalMargin * 2;
}
- frame.setLayoutParams(lp);
+ container.setLayoutParams(lp);
+ Rect bounds = new Rect();
+ container.addOnLayoutChangeListener(
+ (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
+ // Exclude this view (and its horizontal margins) from triggering gestures.
+ // This prevents back gesture from being triggered by dragging close to the
+ // edge of the slider (0% or 100%).
+ bounds.set(-horizontalMargin, 0, right - left + horizontalMargin, bottom - top);
+ v.setSystemGestureExclusionRects(List.of(bounds));
+ });
+ }
+
+ private void setDialogContent(FrameLayout frame) {
+ BrightnessSliderController controller = mToggleSliderFactory.create(this, frame);
+ controller.init();
+ frame.addView(controller.getRootView(), MATCH_PARENT, WRAP_CONTENT);
+ mBrightnessController = mBrightnessControllerFactory.create(controller);
}
private int getWindowAvailableWidth() {
@@ -181,7 +217,9 @@
@Override
protected void onStart() {
super.onStart();
- mBrightnessController.registerCallbacks();
+ if (!QSComposeFragment.isEnabled()) {
+ mBrightnessController.registerCallbacks();
+ }
MetricsLogger.visible(this, MetricsEvent.BRIGHTNESS_DIALOG);
}
@@ -203,7 +241,9 @@
protected void onStop() {
super.onStop();
MetricsLogger.hidden(this, MetricsEvent.BRIGHTNESS_DIALOG);
- mBrightnessController.unregisterCallbacks();
+ if (!QSComposeFragment.isEnabled()) {
+ mBrightnessController.unregisterCallbacks();
+ }
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/settings/brightness/ComposeDialogComposableProvider.kt b/packages/SystemUI/src/com/android/systemui/settings/brightness/ComposeDialogComposableProvider.kt
new file mode 100644
index 0000000..dde2ebc
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/ComposeDialogComposableProvider.kt
@@ -0,0 +1,62 @@
+/*
+ * 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.settings.brightness
+
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.ComposeView
+import androidx.compose.ui.platform.ViewCompositionStrategy
+import com.android.compose.theme.PlatformTheme
+import com.android.systemui.brightness.ui.compose.BrightnessSliderContainer
+import com.android.systemui.brightness.ui.viewmodel.BrightnessSliderViewModel
+import com.android.systemui.lifecycle.rememberViewModel
+import com.android.systemui.qs.ui.composable.QuickSettingsShade
+
+object ComposeDialogComposableProvider {
+
+ fun setComposableBrightness(composeView: ComposeView, content: ComposableProvider) {
+ composeView.apply {
+ setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
+ setContent { PlatformTheme { content.ProvideComposableContent() } }
+ }
+ }
+}
+
+@Composable
+private fun BrightnessSliderForDialog(
+ brightnessSliderViewModelFactory: BrightnessSliderViewModel.Factory
+) {
+ val viewModel =
+ rememberViewModel(traceName = "BrightnessDialog.viewModel") {
+ brightnessSliderViewModelFactory.create(false)
+ }
+ BrightnessSliderContainer(
+ viewModel = viewModel,
+ Modifier.fillMaxWidth().height(QuickSettingsShade.Dimensions.BrightnessSliderHeight),
+ )
+}
+
+class ComposableProvider(
+ private val brightnessSliderViewModelFactory: BrightnessSliderViewModel.Factory
+) {
+ @Composable
+ fun ProvideComposableContent() {
+ BrightnessSliderForDialog(brightnessSliderViewModelFactory)
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/settings/brightness/BrightnessDialogTest.kt b/packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessDialogTest.kt
similarity index 81%
rename from packages/SystemUI/multivalentTests/src/com/android/systemui/settings/brightness/BrightnessDialogTest.kt
rename to packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessDialogTest.kt
index a06784e..f7059e2 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/settings/brightness/BrightnessDialogTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessDialogTest.kt
@@ -18,25 +18,30 @@
import android.content.Intent
import android.graphics.Rect
+import android.platform.test.flag.junit.FlagsParameterization
import android.testing.TestableLooper
import android.view.View
import android.view.ViewGroup
import android.view.WindowManagerPolicyConstants.EXTRA_FROM_BRIGHTNESS_KEY
-import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.FlakyTest
import androidx.test.filters.SmallTest
import androidx.test.rule.ActivityTestRule
import com.android.systemui.SysuiTestCase
import com.android.systemui.activity.SingleActivityFactory
+import com.android.systemui.brightness.ui.viewmodel.BrightnessSliderViewModel
+import com.android.systemui.brightness.ui.viewmodel.brightnessSliderViewModelFactory
+import com.android.systemui.qs.flags.QSComposeFragment
import com.android.systemui.res.R
import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper
+import com.android.systemui.testKosmos
import com.android.systemui.util.concurrency.DelayableExecutor
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.whenever
import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
+import java.util.concurrent.CountDownLatch
import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.flow.MutableStateFlow
@@ -53,11 +58,25 @@
import org.mockito.Mockito.eq
import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
+import platform.test.runner.parameterized.ParameterizedAndroidJunit4
+import platform.test.runner.parameterized.Parameters
@SmallTest
-@RunWith(AndroidJUnit4::class)
+@RunWith(ParameterizedAndroidJunit4::class)
@TestableLooper.RunWithLooper
-class BrightnessDialogTest : SysuiTestCase() {
+class BrightnessDialogTest(val flags: FlagsParameterization) : SysuiTestCase() {
+
+ init {
+ mSetFlagsRule.setFlagsParameterization(flags)
+ }
+
+ val viewId by lazy {
+ if (QSComposeFragment.isEnabled) {
+ R.id.brightness_dialog_slider
+ } else {
+ R.id.brightness_mirror_container
+ }
+ }
@Mock private lateinit var brightnessSliderControllerFactory: BrightnessSliderController.Factory
@Mock private lateinit var brightnessSliderController: BrightnessSliderController
@@ -66,10 +85,14 @@
@Mock private lateinit var accessibilityMgr: AccessibilityManagerWrapper
@Mock private lateinit var shadeInteractor: ShadeInteractor
+ private val kosmos = testKosmos()
+
private val clock = FakeSystemClock()
private val mainExecutor = FakeExecutor(clock)
- @Rule
+ private val onDestroyLatch = CountDownLatch(1)
+
+ @Rule(order = 200)
@JvmField
var activityRule =
ActivityTestRule(
@@ -79,7 +102,9 @@
brightnessControllerFactory,
mainExecutor,
accessibilityMgr,
- shadeInteractor
+ shadeInteractor,
+ kosmos.brightnessSliderViewModelFactory,
+ onDestroyLatch,
)
},
/* initialTouchMode= */ false,
@@ -99,12 +124,13 @@
@After
fun tearDown() {
activityRule.finishActivity()
+ onDestroyLatch.await()
}
@Test
fun testGestureExclusion() {
activityRule.launchActivity(Intent(Intent.ACTION_SHOW_BRIGHTNESS_DIALOG))
- val frame = activityRule.activity.requireViewById<View>(R.id.brightness_mirror_container)
+ val frame = activityRule.activity.requireViewById<View>(viewId)
val lp = frame.layoutParams as ViewGroup.MarginLayoutParams
val horizontalMargin =
@@ -125,7 +151,7 @@
`when`(
accessibilityMgr.getRecommendedTimeoutMillis(
eq(BrightnessDialog.DIALOG_TIMEOUT_MILLIS),
- anyInt()
+ anyInt(),
)
)
.thenReturn(BrightnessDialog.DIALOG_TIMEOUT_MILLIS)
@@ -144,7 +170,7 @@
`when`(
accessibilityMgr.getRecommendedTimeoutMillis(
eq(BrightnessDialog.DIALOG_TIMEOUT_MILLIS),
- anyInt()
+ anyInt(),
)
)
.thenReturn(BrightnessDialog.DIALOG_TIMEOUT_MILLIS)
@@ -171,7 +197,7 @@
`when`(
accessibilityMgr.getRecommendedTimeoutMillis(
eq(BrightnessDialog.DIALOG_TIMEOUT_MILLIS),
- anyInt()
+ anyInt(),
)
)
.thenReturn(BrightnessDialog.DIALOG_TIMEOUT_MILLIS)
@@ -205,14 +231,17 @@
brightnessControllerFactory: BrightnessController.Factory,
mainExecutor: DelayableExecutor,
accessibilityMgr: AccessibilityManagerWrapper,
- shadeInteractor: ShadeInteractor
+ shadeInteractor: ShadeInteractor,
+ brightnessSliderViewModelFactory: BrightnessSliderViewModel.Factory,
+ private val countdownLatch: CountDownLatch,
) :
BrightnessDialog(
brightnessSliderControllerFactory,
brightnessControllerFactory,
mainExecutor,
accessibilityMgr,
- shadeInteractor
+ shadeInteractor,
+ brightnessSliderViewModelFactory,
) {
var finishing = MutableStateFlow(false)
@@ -223,5 +252,18 @@
override fun requestFinish() {
finishing.value = true
}
+
+ override fun onDestroy() {
+ super.onDestroy()
+ countdownLatch.countDown()
+ }
+ }
+
+ companion object {
+ @JvmStatic
+ @Parameters(name = "{0}")
+ fun getParams(): List<FlagsParameterization> {
+ return FlagsParameterization.allCombinationsOf(QSComposeFragment.FLAG_NAME)
+ }
}
}