Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 962bca78 authored by Fabián Kozynski's avatar Fabián Kozynski
Browse files

Brightness dialog use new composable

Test: atest BrightnessDialogTest
Flag: com.android.systemui.qs_ui_refactor_compose_fragment
Fixes: 375193493

Change-Id: I6e2964a45c5b0b95ef33fa989cca8fd7dc992c2c
parent 9d7512ab
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -97,6 +97,7 @@ filegroup {
        "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",
    ],
}

+2 −0
Original line number Diff line number Diff line
@@ -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>
+67 −27
Original line number Diff line number Diff line
@@ -39,10 +39,16 @@ import android.view.WindowMetrics;
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 @@ public class BrightnessDialog extends Activity {
    private final AccessibilityManagerWrapper mAccessibilityMgr;
    private Runnable mCancelTimeoutRunnable;
    private final ShadeInteractor mShadeInteractor;
    private final BrightnessSliderViewModel.Factory mBrightnessSliderViewModelFactory;

    @Inject
    public BrightnessDialog(
@@ -72,13 +79,15 @@ public class BrightnessDialog extends Activity {
            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 @@ public class BrightnessDialog extends Activity {
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setWindowAttributes();
        View view;
        if (!QSComposeFragment.isEnabled()) {
            setContentView(R.layout.brightness_mirror_container);
        setBrightnessDialogViewAttributes();
            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 @@ public class BrightnessDialog extends Activity {
        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,9 +173,21 @@ public class BrightnessDialog extends Activity {
        lp.topMargin = verticalMargin;
        lp.bottomMargin = verticalMargin;

        frame.setLayoutParams(lp);
        Configuration configuration = getResources().getConfiguration();
        int orientation = configuration.orientation;
        int windowWidth = getWindowAvailableWidth();

        if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
            boolean shouldBeFullWidth = getIntent()
                    .getBooleanExtra(EXTRA_BRIGHTNESS_DIALOG_IS_FULL_WIDTH, false);
            lp.width = (shouldBeFullWidth ? windowWidth : windowWidth / 2) - horizontalMargin * 2;
        } else if (orientation == Configuration.ORIENTATION_PORTRAIT) {
            lp.width = windowWidth - horizontalMargin * 2;
        }

        container.setLayoutParams(lp);
        Rect bounds = new Rect();
        frame.addOnLayoutChangeListener(
        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
@@ -146,26 +195,13 @@ public class BrightnessDialog extends Activity {
                    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);

        Configuration configuration = getResources().getConfiguration();
        int orientation = configuration.orientation;
        int windowWidth = getWindowAvailableWidth();

        if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
            boolean shouldBeFullWidth = getIntent()
                    .getBooleanExtra(EXTRA_BRIGHTNESS_DIALOG_IS_FULL_WIDTH, false);
            lp.width = (shouldBeFullWidth ? windowWidth : windowWidth / 2) - horizontalMargin * 2;
        } else if (orientation == Configuration.ORIENTATION_PORTRAIT) {
            lp.width = windowWidth - horizontalMargin * 2;
        }

        frame.setLayoutParams(lp);
    }

    private int getWindowAvailableWidth() {
@@ -181,7 +217,9 @@ public class BrightnessDialog extends Activity {
    @Override
    protected void onStart() {
        super.onStart();
        if (!QSComposeFragment.isEnabled()) {
            mBrightnessController.registerCallbacks();
        }
        MetricsLogger.visible(this, MetricsEvent.BRIGHTNESS_DIALOG);
    }

@@ -203,8 +241,10 @@ public class BrightnessDialog extends Activity {
    protected void onStop() {
        super.onStop();
        MetricsLogger.hidden(this, MetricsEvent.BRIGHTNESS_DIALOG);
        if (!QSComposeFragment.isEnabled()) {
            mBrightnessController.unregisterCallbacks();
        }
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
+62 −0
Original line number Diff line number Diff line
/*
 * 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)
    }
}
+53 −11
Original line number Diff line number Diff line
@@ -18,25 +18,30 @@ package com.android.systemui.settings.brightness

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.anyInt
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 @@ class BrightnessDialogTest : SysuiTestCase() {
    @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 @@ class BrightnessDialogTest : SysuiTestCase() {
                    brightnessControllerFactory,
                    mainExecutor,
                    accessibilityMgr,
                    shadeInteractor
                    shadeInteractor,
                    kosmos.brightnessSliderViewModelFactory,
                    onDestroyLatch,
                )
            },
            /* initialTouchMode= */ false,
@@ -99,12 +124,13 @@ class BrightnessDialogTest : SysuiTestCase() {
    @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 @@ class BrightnessDialogTest : SysuiTestCase() {
        `when`(
                accessibilityMgr.getRecommendedTimeoutMillis(
                    eq(BrightnessDialog.DIALOG_TIMEOUT_MILLIS),
                    anyInt()
                    anyInt(),
                )
            )
            .thenReturn(BrightnessDialog.DIALOG_TIMEOUT_MILLIS)
@@ -144,7 +170,7 @@ class BrightnessDialogTest : SysuiTestCase() {
        `when`(
                accessibilityMgr.getRecommendedTimeoutMillis(
                    eq(BrightnessDialog.DIALOG_TIMEOUT_MILLIS),
                    anyInt()
                    anyInt(),
                )
            )
            .thenReturn(BrightnessDialog.DIALOG_TIMEOUT_MILLIS)
@@ -171,7 +197,7 @@ class BrightnessDialogTest : SysuiTestCase() {
        `when`(
                accessibilityMgr.getRecommendedTimeoutMillis(
                    eq(BrightnessDialog.DIALOG_TIMEOUT_MILLIS),
                    anyInt()
                    anyInt(),
                )
            )
            .thenReturn(BrightnessDialog.DIALOG_TIMEOUT_MILLIS)
@@ -205,14 +231,17 @@ class BrightnessDialogTest : SysuiTestCase() {
        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 @@ class BrightnessDialogTest : SysuiTestCase() {
        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)
        }
    }
}