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

Commit bd856080 authored by Ale Nijamkin's avatar Ale Nijamkin Committed by Android (Google) Code Review
Browse files

Merge changes I0ddce6bd,Iea0cb312 into main

* changes:
  [flexiglass] Changes shade and QS background color.
  [flexiglass] Fixes "wallpaper not visible on AOD" bug.
parents 87a5ae0c a2ae8c65
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -40,7 +40,6 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
@@ -51,6 +50,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.unit.dp
import com.android.compose.animation.scene.SceneScope
import com.android.compose.animation.scene.TransitionState
@@ -62,6 +62,7 @@ import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.qs.footer.ui.compose.FooterActions
import com.android.systemui.qs.ui.viewmodel.QuickSettingsSceneViewModel
import com.android.systemui.res.R
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.ui.composable.ComposableScene
import com.android.systemui.scene.ui.composable.asComposeAware
@@ -168,7 +169,7 @@ private fun SceneScope.QuickSettingsScene(
            modifier =
                Modifier.element(Shade.Elements.BackgroundScrim)
                    .fillMaxSize()
                    .background(MaterialTheme.colorScheme.scrim)
                    .background(colorResource(R.color.shade_scrim_background_dark))
        )
        Column(
            horizontalAlignment = Alignment.CenterHorizontally,
+2 −2
Original line number Diff line number Diff line
@@ -26,7 +26,6 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
@@ -37,6 +36,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.Layout
import androidx.compose.ui.layout.layout
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.unit.dp
import com.android.compose.animation.scene.ElementKey
@@ -171,7 +171,7 @@ private fun SceneScope.ShadeScene(
        modifier =
            modifier
                .element(Shade.Elements.BackgroundScrim)
                .background(MaterialTheme.colorScheme.scrim),
                .background(colorResource(R.color.shade_scrim_background_dark)),
    )
    Box {
        Layout(
+191 −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.
 */

@file:OptIn(ExperimentalCoroutinesApi::class)

package com.android.systemui.scene.domain.interactor

import android.platform.test.annotations.DisableFlags
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.Flags.FLAG_SCENE_CONTAINER
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.deviceentry.data.repository.fakeDeviceEntryRepository
import com.android.systemui.deviceentry.domain.interactor.deviceUnlockedInteractor
import com.android.systemui.flags.EnableSceneContainer
import com.android.systemui.kosmos.testScope
import com.android.systemui.scene.shared.model.ObservableTransitionState
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.fakeSceneDataSource
import com.android.systemui.shade.data.repository.fakeShadeRepository
import com.android.systemui.statusbar.notification.stack.ui.viewmodel.panelExpansionInteractor
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith

@SmallTest
@RunWith(AndroidJUnit4::class)
class PanelExpansionInteractorTest : SysuiTestCase() {

    private val kosmos = testKosmos()
    private val testScope = kosmos.testScope
    private val deviceEntryRepository = kosmos.fakeDeviceEntryRepository
    private val deviceUnlockedInteractor = kosmos.deviceUnlockedInteractor
    private val sceneInteractor = kosmos.sceneInteractor
    private val transitionState =
        MutableStateFlow<ObservableTransitionState>(
            ObservableTransitionState.Idle(SceneKey.Lockscreen)
        )
    private val fakeSceneDataSource = kosmos.fakeSceneDataSource
    private val fakeShadeRepository = kosmos.fakeShadeRepository

    private lateinit var underTest: PanelExpansionInteractor

    @Before
    fun setUp() {
        sceneInteractor.setTransitionState(transitionState)
    }

    @Test
    @EnableSceneContainer
    fun legacyPanelExpansion_whenIdle_whenLocked() =
        testScope.runTest {
            underTest = kosmos.panelExpansionInteractor
            setUnlocked(false)
            val panelExpansion by collectLastValue(underTest.legacyPanelExpansion)

            changeScene(SceneKey.Lockscreen) { assertThat(panelExpansion).isEqualTo(1f) }
            assertThat(panelExpansion).isEqualTo(1f)

            changeScene(SceneKey.Bouncer) { assertThat(panelExpansion).isEqualTo(1f) }
            assertThat(panelExpansion).isEqualTo(1f)

            changeScene(SceneKey.Shade) { assertThat(panelExpansion).isEqualTo(1f) }
            assertThat(panelExpansion).isEqualTo(1f)

            changeScene(SceneKey.QuickSettings) { assertThat(panelExpansion).isEqualTo(1f) }
            assertThat(panelExpansion).isEqualTo(1f)

            changeScene(SceneKey.Communal) { assertThat(panelExpansion).isEqualTo(1f) }
            assertThat(panelExpansion).isEqualTo(1f)
        }

    @Test
    @EnableSceneContainer
    fun legacyPanelExpansion_whenIdle_whenUnlocked() =
        testScope.runTest {
            underTest = kosmos.panelExpansionInteractor
            setUnlocked(true)
            val panelExpansion by collectLastValue(underTest.legacyPanelExpansion)

            changeScene(SceneKey.Gone) { assertThat(panelExpansion).isEqualTo(0f) }
            assertThat(panelExpansion).isEqualTo(0f)

            changeScene(SceneKey.Shade) { progress ->
                assertThat(panelExpansion).isEqualTo(progress)
            }
            assertThat(panelExpansion).isEqualTo(1f)

            changeScene(SceneKey.QuickSettings) {
                // Shade's already expanded, so moving to QS should also be 1f.
                assertThat(panelExpansion).isEqualTo(1f)
            }
            assertThat(panelExpansion).isEqualTo(1f)

            changeScene(SceneKey.Communal) { assertThat(panelExpansion).isEqualTo(1f) }
            assertThat(panelExpansion).isEqualTo(1f)
        }

    @Test
    @DisableFlags(FLAG_SCENE_CONTAINER)
    fun legacyPanelExpansion_whenInLegacyMode() =
        testScope.runTest {
            underTest = kosmos.panelExpansionInteractor
            val leet = 0.1337f
            fakeShadeRepository.setLegacyShadeExpansion(leet)
            setUnlocked(false)
            val panelExpansion by collectLastValue(underTest.legacyPanelExpansion)

            changeScene(SceneKey.Lockscreen)
            assertThat(panelExpansion).isEqualTo(leet)

            changeScene(SceneKey.Bouncer)
            assertThat(panelExpansion).isEqualTo(leet)

            changeScene(SceneKey.Shade)
            assertThat(panelExpansion).isEqualTo(leet)

            changeScene(SceneKey.QuickSettings)
            assertThat(panelExpansion).isEqualTo(leet)

            changeScene(SceneKey.Communal)
            assertThat(panelExpansion).isEqualTo(leet)
        }

    private fun TestScope.setUnlocked(isUnlocked: Boolean) {
        val isDeviceUnlocked by collectLastValue(deviceUnlockedInteractor.isDeviceUnlocked)
        deviceEntryRepository.setUnlocked(isUnlocked)
        runCurrent()

        assertThat(isDeviceUnlocked).isEqualTo(isUnlocked)
    }

    private fun TestScope.changeScene(
        toScene: SceneKey,
        assertDuringProgress: ((progress: Float) -> Unit) = {},
    ) {
        val currentScene by collectLastValue(sceneInteractor.currentScene)
        val progressFlow = MutableStateFlow(0f)
        transitionState.value =
            ObservableTransitionState.Transition(
                fromScene = checkNotNull(currentScene),
                toScene = toScene,
                progress = progressFlow,
                isInitiatedByUserInput = true,
                isUserInputOngoing = flowOf(true),
            )
        runCurrent()
        assertDuringProgress(progressFlow.value)

        progressFlow.value = 0.2f
        runCurrent()
        assertDuringProgress(progressFlow.value)

        progressFlow.value = 0.6f
        runCurrent()
        assertDuringProgress(progressFlow.value)

        progressFlow.value = 1f
        runCurrent()
        assertDuringProgress(progressFlow.value)

        transitionState.value = ObservableTransitionState.Idle(toScene)
        fakeSceneDataSource.changeScene(toScene)
        runCurrent()
        assertDuringProgress(progressFlow.value)

        assertThat(currentScene).isEqualTo(toScene)
    }
}
+104 −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.
 */

@file:OptIn(ExperimentalCoroutinesApi::class)

package com.android.systemui.scene.domain.interactor

import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.scene.shared.model.ObservableTransitionState
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.shade.data.repository.ShadeRepository
import javax.inject.Inject
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map

@SysUISingleton
class PanelExpansionInteractor
@Inject
constructor(
    sceneInteractor: SceneInteractor,
    shadeRepository: ShadeRepository,
) {

    /**
     * The amount by which the "panel" has been expanded (`0` when fully collapsed, `1` when fully
     * expanded).
     *
     * This is a legacy concept from the time when the "panel" included the notification/QS shades
     * as well as the keyguard (lockscreen and bouncer). This value is meant only for
     * backwards-compatibility and should not be consumed by newer code.
     */
    @Deprecated("Use SceneInteractor.currentScene instead.")
    val legacyPanelExpansion: Flow<Float> =
        if (SceneContainerFlag.isEnabled) {
            sceneInteractor.transitionState.flatMapLatest { state ->
                when (state) {
                    is ObservableTransitionState.Idle ->
                        flowOf(
                            if (state.scene != SceneKey.Gone) {
                                // When resting on a non-Gone scene, the panel is fully expanded.
                                1f
                            } else {
                                // When resting on the Gone scene, the panel is considered fully
                                // collapsed.
                                0f
                            }
                        )
                    is ObservableTransitionState.Transition ->
                        when {
                            state.fromScene == SceneKey.Gone ->
                                if (state.toScene.isExpandable()) {
                                    // Moving from Gone to a scene that can animate-expand has a
                                    // panel
                                    // expansion
                                    // that tracks with the transition.
                                    state.progress
                                } else {
                                    // Moving from Gone to a scene that doesn't animate-expand
                                    // immediately makes
                                    // the panel fully expanded.
                                    flowOf(1f)
                                }
                            state.toScene == SceneKey.Gone ->
                                if (state.fromScene.isExpandable()) {
                                    // Moving to Gone from a scene that can animate-expand has a
                                    // panel
                                    // expansion
                                    // that tracks with the transition.
                                    state.progress.map { 1 - it }
                                } else {
                                    // Moving to Gone from a scene that doesn't animate-expand
                                    // immediately makes
                                    // the panel fully collapsed.
                                    flowOf(0f)
                                }
                            else -> flowOf(1f)
                        }
                }
            }
        } else {
            shadeRepository.legacyShadeExpansion
        }

    private fun SceneKey.isExpandable(): Boolean {
        return this == SceneKey.Shade || this == SceneKey.QuickSettings
    }
}
+33 −7
Original line number Diff line number Diff line
@@ -19,8 +19,11 @@ package com.android.systemui.shade.transition
import android.content.Context
import android.content.res.Configuration
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dump.DumpManager
import com.android.systemui.plugins.qs.QS
import com.android.systemui.scene.domain.interactor.PanelExpansionInteractor
import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.shade.PanelState
import com.android.systemui.shade.ShadeExpansionChangeEvent
import com.android.systemui.shade.ShadeExpansionStateManager
@@ -31,21 +34,26 @@ import com.android.systemui.statusbar.SysuiStatusBarStateController
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.statusbar.policy.SplitShadeStateController
import dagger.Lazy
import java.io.PrintWriter
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch

/** Controls the shade expansion transition on non-lockscreen. */
@SysUISingleton
class ShadeTransitionController
@Inject
constructor(
    @Application private val applicationScope: CoroutineScope,
    configurationController: ConfigurationController,
    shadeExpansionStateManager: ShadeExpansionStateManager,
    dumpManager: DumpManager,
    private val context: Context,
    private val scrimShadeTransitionController: ScrimShadeTransitionController,
    private val statusBarStateController: SysuiStatusBarStateController,
    private val splitShadeStateController: SplitShadeStateController
    private val splitShadeStateController: SplitShadeStateController,
    private val panelExpansionInteractor: Lazy<PanelExpansionInteractor>,
) {

    lateinit var shadeViewController: ShadeViewController
@@ -63,11 +71,27 @@ constructor(
                override fun onConfigChanged(newConfig: Configuration?) {
                    updateResources()
                }
            })
            }
        )
        if (SceneContainerFlag.isEnabled) {
            applicationScope.launch {
                panelExpansionInteractor.get().legacyPanelExpansion.collect { panelExpansion ->
                    onPanelExpansionChanged(
                        ShadeExpansionChangeEvent(
                            fraction = panelExpansion,
                            expanded = panelExpansion > 0f,
                            tracking = true,
                            dragDownPxAmount = 0f,
                        )
                    )
                }
            }
        } else {
            val currentState =
                shadeExpansionStateManager.addExpansionListener(this::onPanelExpansionChanged)
            onPanelExpansionChanged(currentState)
            shadeExpansionStateManager.addStateListener(this::onPanelStateChanged)
        }
        dumpManager.registerCriticalDumpable("ShadeTransitionController") { printWriter, _ ->
            dump(printWriter)
        }
@@ -98,7 +122,9 @@ constructor(
                qs.isInitialized: ${this::qs.isInitialized}
                npvc.isInitialized: ${this::shadeViewController.isInitialized}
                nssl.isInitialized: ${this::notificationStackScrollLayoutController.isInitialized}
            """.trimIndent())
            """
                .trimIndent()
        )
    }

    private fun isScreenUnlocked() =
Loading