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

Commit bce2c043 authored by Fabian Kozynski's avatar Fabian Kozynski Committed by Android (Google) Code Review
Browse files

Merge changes from topic "349794543" into main

* changes:
  Implement QQS for BC25
  Fix some organization of view model
parents 89da0783 6e7d051f
Loading
Loading
Loading
Loading
+17 −23
Original line number Diff line number Diff line
@@ -16,14 +16,14 @@

package com.android.systemui.qs.ui.composable

import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.AnimatedContent
import androidx.compose.animation.EnterTransition
import androidx.compose.animation.ExitTransition
import androidx.compose.animation.core.tween
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.togetherWith
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
@@ -46,6 +46,9 @@ import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.ui.composable.LockscreenContent
import com.android.systemui.qs.panels.ui.compose.EditMode
import com.android.systemui.qs.panels.ui.compose.TileGrid
import com.android.systemui.qs.ui.composable.QuickSettingsShade.Transitions.QuickSettingsLayoutEnter
import com.android.systemui.qs.ui.composable.QuickSettingsShade.Transitions.QuickSettingsLayoutExit
import com.android.systemui.qs.ui.viewmodel.QuickSettingsContainerViewModel
import com.android.systemui.qs.ui.viewmodel.QuickSettingsShadeSceneViewModel
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.scene.ui.composable.ComposableScene
@@ -95,7 +98,7 @@ constructor(
                )

                ShadeBody(
                    viewModel = viewModel,
                    viewModel = viewModel.quickSettingsContainerViewModel,
                )
            }
        }
@@ -104,39 +107,30 @@ constructor(

@Composable
private fun ShadeBody(
    viewModel: QuickSettingsShadeSceneViewModel,
    viewModel: QuickSettingsContainerViewModel,
) {
    val isEditing by viewModel.editModeViewModel.isEditing.collectAsStateWithLifecycle()

    Box {
        // The main Quick Settings grid layout.
        AnimatedVisibility(
            visible = !isEditing,
            enter = QuickSettingsShade.Transitions.QuickSettingsLayoutEnter,
            exit = QuickSettingsShade.Transitions.QuickSettingsLayoutExit,
        ) {
            QuickSettingsLayout(
                viewModel = viewModel,
            )
        }

        // The Quick Settings Editor layout.
        AnimatedVisibility(
            visible = isEditing,
            enter = QuickSettingsShade.Transitions.QuickSettingsEditorEnter,
            exit = QuickSettingsShade.Transitions.QuickSettingsEditorExit,
        ) {
    AnimatedContent(
        targetState = isEditing,
        transitionSpec = { QuickSettingsLayoutEnter togetherWith QuickSettingsLayoutExit }
    ) { editing ->
        if (editing) {
            EditMode(
                viewModel = viewModel.editModeViewModel,
                modifier = Modifier.fillMaxWidth().padding(QuickSettingsShade.Dimensions.Padding)
            )
        } else {
            QuickSettingsLayout(
                viewModel = viewModel,
            )
        }
    }
}

@Composable
private fun QuickSettingsLayout(
    viewModel: QuickSettingsShadeSceneViewModel,
    viewModel: QuickSettingsContainerViewModel,
    modifier: Modifier = Modifier,
) {
    Column(
+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.qs.panels.data.repository

import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.kosmos.testCase
import com.android.systemui.kosmos.testScope
import com.android.systemui.res.R
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.test.runTest
import org.junit.Test
import org.junit.runner.RunWith

@SmallTest
@RunWith(AndroidJUnit4::class)
class QuickQuickSettingsRowRepositoryTest : SysuiTestCase() {
    private val kosmos = testKosmos()

    private val underTest = kosmos.quickQuickSettingsRowRepository

    @Test
    fun rows_followsConfig() =
        with(kosmos) {
            testScope.runTest {
                val rows by collectLastValue(underTest.rows)

                setRowsInConfig(2)
                assertThat(rows).isEqualTo(2)

                setRowsInConfig(3)
                assertThat(rows).isEqualTo(3)
            }
        }

    private fun setRowsInConfig(rows: Int) =
        with(kosmos) {
            testCase.context.orCreateTestableResources.addOverride(
                R.integer.quick_qs_panel_max_rows,
                rows,
            )
            fakeConfigurationRepository.onConfigurationChange()
        }
}
+163 −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.qs.panels.ui.viewmodel

import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.testCase
import com.android.systemui.kosmos.testScope
import com.android.systemui.qs.panels.data.repository.IconTilesRepository
import com.android.systemui.qs.panels.data.repository.iconTilesRepository
import com.android.systemui.qs.pipeline.domain.interactor.currentTilesInteractor
import com.android.systemui.qs.pipeline.shared.TileSpec
import com.android.systemui.res.R
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith

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

    private val kosmos =
        testKosmos().apply {
            iconTilesRepository =
                object : IconTilesRepository {
                    override fun isIconTile(spec: TileSpec): Boolean {
                        return spec.spec.startsWith(PREFIX_SMALL)
                    }
                }
        }

    private val underTest = kosmos.quickQuickSettingsViewModel

    private val tiles =
        listOf(
                "$PREFIX_SMALL:1",
                "$PREFIX_SMALL:2",
                "$PREFIX_LARGE:3",
                "$PREFIX_SMALL:4",
                "$PREFIX_LARGE:5",
                "$PREFIX_LARGE:6",
                "$PREFIX_SMALL:7",
                "$PREFIX_SMALL:8",
                "$PREFIX_LARGE:9",
            )
            .map(TileSpec::create)

    @Before
    fun setUp() {
        kosmos.setTiles(tiles)
    }

    @Test
    fun splitIntoRows_onlyFirstTwoRowsOfTiles() =
        with(kosmos) {
            testScope.runTest {
                setRows(2)
                val columns by collectLastValue(underTest.columns)
                val tileViewModels by collectLastValue(underTest.tileViewModels)

                assertThat(columns).isEqualTo(4)
                // All tiles in 4 columns
                // [1] [2] [3 3]
                // [4] [5 5]
                // [6 6] [7] [8]
                // [9 9]

                assertThat(tileViewModels!!.map { it.tile.spec }).isEqualTo(tiles.take(5))
            }
        }

    @Test
    fun changeRows_tilesChange() =
        with(kosmos) {
            testScope.runTest {
                setRows(2)
                val columns by collectLastValue(underTest.columns)
                val tileViewModels by collectLastValue(underTest.tileViewModels)

                assertThat(columns).isEqualTo(4)
                // All tiles in 4 columns
                // [1] [2] [3 3]
                // [4] [5 5]
                // [6 6] [7] [8]
                // [9 9]

                setRows(3)
                assertThat(tileViewModels!!.map { it.tile.spec }).isEqualTo(tiles.take(8))
                setRows(1)
                assertThat(tileViewModels!!.map { it.tile.spec }).isEqualTo(tiles.take(3))
            }
        }

    @Test
    fun changeTiles_tilesChange() =
        with(kosmos) {
            testScope.runTest {
                setRows(2)
                val columns by collectLastValue(underTest.columns)
                val tileViewModels by collectLastValue(underTest.tileViewModels)

                assertThat(columns).isEqualTo(4)
                // All tiles in 4 columns
                // [1] [2] [3 3]
                // [4] [5 5]
                // [6 6] [7] [8]
                // [9 9]

                // Remove tile small:4
                currentTilesInteractor.removeTiles(setOf(tiles[3]))

                assertThat(tileViewModels!!.map { it.tile.spec })
                    .isEqualTo(
                        listOf(
                                "$PREFIX_SMALL:1",
                                "$PREFIX_SMALL:2",
                                "$PREFIX_LARGE:3",
                                "$PREFIX_LARGE:5",
                                "$PREFIX_LARGE:6",
                            )
                            .map(TileSpec::create)
                    )
            }
        }

    private fun Kosmos.setTiles(tiles: List<TileSpec>) {
        currentTilesInteractor.setTiles(tiles)
    }

    private fun Kosmos.setRows(rows: Int) {
        testCase.context.orCreateTestableResources.addOverride(
            R.integer.quick_qs_panel_max_rows,
            rows,
        )
        fakeConfigurationRepository.onConfigurationChange()
    }

    private companion object {
        const val PREFIX_SMALL = "small"
        const val PREFIX_LARGE = "large"
    }
}
+20 −1
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.systemui.qs.ui.viewmodel
import android.testing.TestableLooper
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.compose.animation.scene.Back
import com.android.compose.animation.scene.Swipe
import com.android.systemui.SysuiTestCase
import com.android.systemui.authentication.data.repository.fakeAuthenticationRepository
@@ -31,12 +32,12 @@ import com.android.systemui.keyguard.data.repository.fakeDeviceEntryFingerprintA
import com.android.systemui.keyguard.domain.interactor.keyguardEnabledInteractor
import com.android.systemui.keyguard.shared.model.SuccessFingerprintAuthenticationStatus
import com.android.systemui.kosmos.testScope
import com.android.systemui.qs.panels.ui.viewmodel.editModeViewModel
import com.android.systemui.scene.domain.interactor.sceneInteractor
import com.android.systemui.scene.domain.resolver.homeSceneFamilyResolver
import com.android.systemui.scene.shared.model.SceneFamilies
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.shade.data.repository.fakeShadeRepository
import com.android.systemui.shade.ui.viewmodel.quickSettingsShadeSceneViewModel
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -155,6 +156,24 @@ class QuickSettingsShadeSceneViewModelTest : SysuiTestCase() {
            assertThat(homeScene).isEqualTo(Scenes.Gone)
        }

    @Test
    fun backTransitionSceneKey_notEditing_Home() =
        testScope.runTest {
            val destinationScenes by collectLastValue(underTest.destinationScenes)

            assertThat(destinationScenes?.get(Back)?.toScene).isEqualTo(SceneFamilies.Home)
        }

    @Test
    fun backTransition_editing_noDestination() =
        testScope.runTest {
            val destinationScenes by collectLastValue(underTest.destinationScenes)
            kosmos.editModeViewModel.startEditing()

            assertThat(destinationScenes!!).isNotEmpty()
            assertThat(destinationScenes?.get(Back)).isNull()
        }

    private fun TestScope.lockDevice() {
        val deviceUnlockStatus by collectLastValue(deviceUnlockedInteractor.deviceUnlockStatus)

+1 −1
Original line number Diff line number Diff line
@@ -74,7 +74,7 @@ interface PanelsModule {

    @Binds
    @PaginatedBaseLayoutType
    fun bindPaginatedBaseGridLayout(impl: PartitionedGridLayout): PaginatableGridLayout
    fun bindPaginatedBaseGridLayout(impl: InfiniteGridLayout): PaginatableGridLayout

    @Binds
    @PaginatedBaseLayoutType
Loading