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

Commit d245ac99 authored by Olivier St-Onge's avatar Olivier St-Onge
Browse files

Implement grid consistency interactor.

The idea is that each grid type will have its own way to reorder tiles to ensure a correct layout.
The Infinite grid consistency interactor will attempt to reorder tiles to fill in all columns of each row.

Flag: ACONFIG com.android.systemui.qs_ui_refactor DEVELOPMENT
Test: manually with QSActivity
Bug: 338588826

Change-Id: I05fdf2bcf83cadb2fbea7447a02280f6f74cab7d
parent e5b74662
Loading
Loading
Loading
Loading
+39 −0
Original line number Diff line number Diff line
@@ -16,8 +16,17 @@

package com.android.systemui.qs.panels.dagger

import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.LogBufferFactory
import com.android.systemui.qs.panels.data.repository.GridLayoutTypeRepository
import com.android.systemui.qs.panels.data.repository.GridLayoutTypeRepositoryImpl
import com.android.systemui.qs.panels.data.repository.IconTilesRepository
import com.android.systemui.qs.panels.data.repository.IconTilesRepositoryImpl
import com.android.systemui.qs.panels.domain.interactor.GridTypeConsistencyInteractor
import com.android.systemui.qs.panels.domain.interactor.InfiniteGridConsistencyInteractor
import com.android.systemui.qs.panels.domain.interactor.NoopGridConsistencyInteractor
import com.android.systemui.qs.panels.shared.model.GridConsistencyLog
import com.android.systemui.qs.panels.shared.model.GridLayoutType
import com.android.systemui.qs.panels.shared.model.InfiniteGridLayoutType
import com.android.systemui.qs.panels.ui.compose.GridLayout
@@ -31,7 +40,22 @@ import dagger.multibindings.IntoSet
interface PanelsModule {
    @Binds fun bindIconTilesRepository(impl: IconTilesRepositoryImpl): IconTilesRepository

    @Binds
    fun bindGridLayoutTypeRepository(impl: GridLayoutTypeRepositoryImpl): GridLayoutTypeRepository

    @Binds
    fun bindDefaultGridConsistencyInteractor(
        impl: NoopGridConsistencyInteractor
    ): GridTypeConsistencyInteractor

    companion object {
        @Provides
        @SysUISingleton
        @GridConsistencyLog
        fun providesGridConsistencyLog(factory: LogBufferFactory): LogBuffer {
            return factory.create("GridConsistencyLog", 50)
        }

        @Provides
        @IntoSet
        fun provideGridLayout(gridLayout: InfiniteGridLayout): Pair<GridLayoutType, GridLayout> {
@@ -44,5 +68,20 @@ interface PanelsModule {
        ): Map<GridLayoutType, GridLayout> {
            return entries.toMap()
        }

        @Provides
        @IntoSet
        fun provideGridConsistencyInteractor(
            consistencyInteractor: InfiniteGridConsistencyInteractor
        ): Pair<GridLayoutType, GridTypeConsistencyInteractor> {
            return Pair(InfiniteGridLayoutType, consistencyInteractor)
        }

        @Provides
        fun provideGridConsistencyInteractorMap(
            entries: Set<@JvmSuppressWildcards Pair<GridLayoutType, GridTypeConsistencyInteractor>>
        ): Map<GridLayoutType, GridTypeConsistencyInteractor> {
            return entries.toMap()
        }
    }
}
+10 −4
Original line number Diff line number Diff line
@@ -20,10 +20,16 @@ import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.qs.panels.shared.model.GridLayoutType
import com.android.systemui.qs.panels.shared.model.InfiniteGridLayoutType
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow

interface GridLayoutTypeRepository {
    val layout: StateFlow<GridLayoutType>
}

@SysUISingleton
class GridLayoutTypeRepository @Inject constructor() {
    val layout: Flow<GridLayoutType> = flowOf(InfiniteGridLayoutType)
class GridLayoutTypeRepositoryImpl @Inject constructor() : GridLayoutTypeRepository {
    private val _layout: MutableStateFlow<GridLayoutType> = MutableStateFlow(InfiniteGridLayoutType)
    override val layout = _layout.asStateFlow()
}
+9 −6
Original line number Diff line number Diff line
@@ -19,20 +19,20 @@ package com.android.systemui.qs.panels.data.repository
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.qs.pipeline.shared.TileSpec
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow

/** Repository for retrieving the list of [TileSpec] to be displayed as icons. */
interface IconTilesRepository {
    val iconTilesSpecs: Flow<Set<TileSpec>>
    val iconTilesSpecs: StateFlow<Set<TileSpec>>
}

@SysUISingleton
class IconTilesRepositoryImpl @Inject constructor() : IconTilesRepository {

    /** Set of toggleable tiles that are suitable for being shown as an icon. */
    override val iconTilesSpecs: Flow<Set<TileSpec>> =
        flowOf(
    private val _iconTilesSpecs =
        MutableStateFlow(
            setOf(
                TileSpec.create("airplane"),
                TileSpec.create("battery"),
@@ -50,4 +50,7 @@ class IconTilesRepositoryImpl @Inject constructor() : IconTilesRepository {
                TileSpec.create("rotation")
            )
        )

    /** Set of toggleable tiles that are suitable for being shown as an icon. */
    override val iconTilesSpecs: StateFlow<Set<TileSpec>> = _iconTilesSpecs.asStateFlow()
}
+30 −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 com.android.systemui.dagger.SysUISingleton
import javax.inject.Inject
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow

@SysUISingleton
class InfiniteGridSizeRepository @Inject constructor() {
    // Number of columns in the narrowest state for consistency
    private val _columns = MutableStateFlow(4)
    val columns: StateFlow<Int> = _columns.asStateFlow()
}
+75 −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.domain.interactor

import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.core.LogLevel
import com.android.systemui.qs.panels.shared.model.GridConsistencyLog
import com.android.systemui.qs.panels.shared.model.GridLayoutType
import com.android.systemui.qs.pipeline.domain.interactor.CurrentTilesInteractor
import com.android.systemui.qs.pipeline.shared.TileSpec
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch

@SysUISingleton
class GridConsistencyInteractor
@Inject
constructor(
    private val gridLayoutTypeInteractor: GridLayoutTypeInteractor,
    private val currentTilesInteractor: CurrentTilesInteractor,
    private val consistencyInteractors:
        Map<GridLayoutType, @JvmSuppressWildcards GridTypeConsistencyInteractor>,
    private val defaultConsistencyInteractor: GridTypeConsistencyInteractor,
    @GridConsistencyLog private val logBuffer: LogBuffer,
    @Application private val applicationScope: CoroutineScope,
) {
    fun start() {
        applicationScope.launch {
            gridLayoutTypeInteractor.layout.collectLatest { type ->
                val consistencyInteractor =
                    consistencyInteractors[type] ?: defaultConsistencyInteractor
                currentTilesInteractor.currentTiles
                    .map { tiles -> tiles.map { it.spec } }
                    .collectLatest { tiles ->
                        val newTiles = consistencyInteractor.reconcileTiles(tiles)
                        if (newTiles != tiles) {
                            currentTilesInteractor.setTiles(newTiles)
                            logChange(newTiles)
                        }
                    }
            }
        }
    }

    private fun logChange(tiles: List<TileSpec>) {
        logBuffer.log(
            LOG_BUFFER_CURRENT_TILES_CHANGE_TAG,
            LogLevel.DEBUG,
            { str1 = tiles.toString() },
            { "Tiles reordered: $str1" }
        )
    }

    private companion object {
        const val LOG_BUFFER_CURRENT_TILES_CHANGE_TAG = "GridConsistencyTilesChange"
    }
}
Loading