diff options
| author | 2023-11-13 17:47:01 +0000 | |
|---|---|---|
| committer | 2023-11-13 17:47:01 +0000 | |
| commit | e968b57b2d294f85956040389f9d3db464360e51 (patch) | |
| tree | d154feaf1fc107cebbb0da0fcb246e379efcf2f7 | |
| parent | fddb69d396bbd3784003797a18e54a6a7e3e2db5 (diff) | |
| parent | d95160a85163f3c7d47656ad2591a00eeafe57fe (diff) | |
Merge "Update NewQSTileFactory and QSTileConfigProvider to provide custom tile ViewModel" into main
11 files changed, 114 insertions, 33 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelFactory.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelFactory.kt index 736f7cfbfce9..ae554d954580 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelFactory.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelFactory.kt @@ -26,6 +26,7 @@ import com.android.systemui.qs.tiles.base.interactor.QSTileDataToStateMapper import com.android.systemui.qs.tiles.base.interactor.QSTileUserActionInteractor import com.android.systemui.qs.tiles.base.logging.QSTileLogger import com.android.systemui.qs.tiles.impl.di.QSTileComponent +import com.android.systemui.qs.tiles.viewmodel.QSTileConfig import com.android.systemui.qs.tiles.viewmodel.QSTileConfigProvider import com.android.systemui.qs.tiles.viewmodel.QSTileState import com.android.systemui.user.data.repository.UserRepository @@ -60,12 +61,17 @@ sealed interface QSTileViewModelFactory<T> { ) : QSTileViewModelFactory<T> { /** - * Creates [QSTileViewModelImpl] based on the interactors obtained from [component]. - * Reference of that [component] is then stored along the view model. + * Creates [QSTileViewModelImpl] based on the interactors obtained from [QSTileComponent]. + * Reference of that [QSTileComponent] is then stored along the view model. */ - fun create(tileSpec: TileSpec, component: QSTileComponent<T>): QSTileViewModelImpl<T> = - QSTileViewModelImpl( - qsTileConfigProvider.getConfig(tileSpec.spec), + fun create( + tileSpec: TileSpec, + componentFactory: (config: QSTileConfig) -> QSTileComponent<T> + ): QSTileViewModelImpl<T> { + val config = qsTileConfigProvider.getConfig(tileSpec.spec) + val component = componentFactory(config) + return QSTileViewModelImpl( + config, component::userActionInteractor, component::dataInteractor, component::dataToStateMapper, @@ -77,6 +83,7 @@ sealed interface QSTileViewModelFactory<T> { systemClock, backgroundDispatcher, ) + } } /** diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/di/NewQSTileFactory.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/di/NewQSTileFactory.kt index 7d7af64a3038..27007bbf7aee 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/di/NewQSTileFactory.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/di/NewQSTileFactory.kt @@ -19,6 +19,11 @@ package com.android.systemui.qs.tiles.di import com.android.systemui.dagger.SysUISingleton import com.android.systemui.plugins.qs.QSFactory import com.android.systemui.plugins.qs.QSTile +import com.android.systemui.qs.pipeline.shared.TileSpec +import com.android.systemui.qs.tiles.base.viewmodel.QSTileViewModelFactory +import com.android.systemui.qs.tiles.impl.custom.di.CustomTileComponent +import com.android.systemui.qs.tiles.impl.custom.di.QSTileConfigModule +import com.android.systemui.qs.tiles.impl.custom.domain.entity.CustomTileDataModel import com.android.systemui.qs.tiles.viewmodel.QSTileConfigProvider import com.android.systemui.qs.tiles.viewmodel.QSTileViewModel import com.android.systemui.qs.tiles.viewmodel.QSTileViewModelAdapter @@ -34,18 +39,31 @@ constructor( private val adapterFactory: QSTileViewModelAdapter.Factory, private val tileMap: Map<String, @JvmSuppressWildcards Provider<@JvmSuppressWildcards QSTileViewModel>>, + private val customTileComponentBuilder: CustomTileComponent.Builder, + private val customTileViewModelFactory: QSTileViewModelFactory.Component<CustomTileDataModel>, ) : QSFactory { init { for (viewModelTileSpec in tileMap.keys) { - // throws an exception when there is no config for a tileSpec of an injected viewModel - qsTileConfigProvider.getConfig(viewModelTileSpec) + require(qsTileConfigProvider.hasConfig(viewModelTileSpec)) { + "No config for $viewModelTileSpec" + } } } - override fun createTile(tileSpec: String): QSTile? = - tileMap[tileSpec]?.let { - val tile = it.get() - adapterFactory.create(tile) + override fun createTile(tileSpec: String): QSTile? { + val viewModel: QSTileViewModel = + when (val spec = TileSpec.create(tileSpec)) { + is TileSpec.CustomTileSpec -> createCustomTileViewModel(spec) + is TileSpec.PlatformTileSpec -> tileMap[tileSpec]?.get() + is TileSpec.Invalid -> null + } + ?: return null + return adapterFactory.create(viewModel) + } + + private fun createCustomTileViewModel(spec: TileSpec.CustomTileSpec): QSTileViewModel = + customTileViewModelFactory.create(spec) { config -> + customTileComponentBuilder.qsTileConfigModule(QSTileConfigModule(config)).build() } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/CustomTileInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/CustomTileInteractor.kt index 761274e96e43..14bf25d10d88 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/CustomTileInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/CustomTileInteractor.kt @@ -19,17 +19,18 @@ package com.android.systemui.qs.tiles.impl.custom import android.os.UserHandle import com.android.systemui.qs.tiles.base.interactor.DataUpdateTrigger import com.android.systemui.qs.tiles.base.interactor.QSTileDataInteractor +import com.android.systemui.qs.tiles.impl.custom.domain.entity.CustomTileDataModel import com.android.systemui.qs.tiles.impl.di.QSTileScope import javax.inject.Inject import kotlinx.coroutines.flow.Flow @QSTileScope -class CustomTileInteractor @Inject constructor() : QSTileDataInteractor<CustomTileData> { +class CustomTileInteractor @Inject constructor() : QSTileDataInteractor<CustomTileDataModel> { override fun tileData( user: UserHandle, triggers: Flow<DataUpdateTrigger> - ): Flow<CustomTileData> { + ): Flow<CustomTileDataModel> { TODO("Not yet implemented") } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/CustomTileMapper.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/CustomTileMapper.kt index f7bec024b7bb..e23a5c2f0b6a 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/CustomTileMapper.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/CustomTileMapper.kt @@ -17,15 +17,16 @@ package com.android.systemui.qs.tiles.impl.custom import com.android.systemui.qs.tiles.base.interactor.QSTileDataToStateMapper +import com.android.systemui.qs.tiles.impl.custom.domain.entity.CustomTileDataModel import com.android.systemui.qs.tiles.impl.di.QSTileScope import com.android.systemui.qs.tiles.viewmodel.QSTileConfig import com.android.systemui.qs.tiles.viewmodel.QSTileState import javax.inject.Inject @QSTileScope -class CustomTileMapper @Inject constructor() : QSTileDataToStateMapper<CustomTileData> { +class CustomTileMapper @Inject constructor() : QSTileDataToStateMapper<CustomTileDataModel> { - override fun map(config: QSTileConfig, data: CustomTileData): QSTileState { + override fun map(config: QSTileConfig, data: CustomTileDataModel): QSTileState { TODO("Not yet implemented") } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/CustomTileUserActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/CustomTileUserActionInteractor.kt index 6c1c1a34abc0..f34704be8bc5 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/CustomTileUserActionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/CustomTileUserActionInteractor.kt @@ -18,14 +18,15 @@ package com.android.systemui.qs.tiles.impl.custom import com.android.systemui.qs.tiles.base.interactor.QSTileInput import com.android.systemui.qs.tiles.base.interactor.QSTileUserActionInteractor +import com.android.systemui.qs.tiles.impl.custom.domain.entity.CustomTileDataModel import com.android.systemui.qs.tiles.impl.di.QSTileScope import javax.inject.Inject @QSTileScope class CustomTileUserActionInteractor @Inject constructor() : - QSTileUserActionInteractor<CustomTileData> { + QSTileUserActionInteractor<CustomTileDataModel> { - override suspend fun handleInput(input: QSTileInput<CustomTileData>) { + override suspend fun handleInput(input: QSTileInput<CustomTileDataModel>) { TODO("Not yet implemented") } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/di/CustomTileComponent.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/di/CustomTileComponent.kt index 01df90662579..88bc8fa81e1a 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/di/CustomTileComponent.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/di/CustomTileComponent.kt @@ -16,13 +16,14 @@ package com.android.systemui.qs.tiles.impl.custom.di +import com.android.systemui.qs.tiles.impl.custom.domain.entity.CustomTileDataModel import com.android.systemui.qs.tiles.impl.di.QSTileComponent import com.android.systemui.qs.tiles.impl.di.QSTileScope import dagger.Subcomponent @QSTileScope @Subcomponent(modules = [QSTileConfigModule::class, CustomTileModule::class]) -interface CustomTileComponent : QSTileComponent<Any> { +interface CustomTileComponent : QSTileComponent<CustomTileDataModel> { @Subcomponent.Builder interface Builder { diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/di/CustomTileModule.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/di/CustomTileModule.kt index 482bf9bcd051..83767aa9d444 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/di/CustomTileModule.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/di/CustomTileModule.kt @@ -19,13 +19,13 @@ package com.android.systemui.qs.tiles.impl.custom.di import com.android.systemui.qs.tiles.base.interactor.QSTileDataInteractor import com.android.systemui.qs.tiles.base.interactor.QSTileDataToStateMapper import com.android.systemui.qs.tiles.base.interactor.QSTileUserActionInteractor -import com.android.systemui.qs.tiles.impl.custom.CustomTileData import com.android.systemui.qs.tiles.impl.custom.CustomTileInteractor import com.android.systemui.qs.tiles.impl.custom.CustomTileMapper import com.android.systemui.qs.tiles.impl.custom.CustomTileUserActionInteractor import com.android.systemui.qs.tiles.impl.custom.data.repository.CustomTileDefaultsRepository import com.android.systemui.qs.tiles.impl.custom.data.repository.CustomTileDefaultsRepositoryImpl import com.android.systemui.qs.tiles.impl.custom.di.bound.CustomTileBoundComponent +import com.android.systemui.qs.tiles.impl.custom.domain.entity.CustomTileDataModel import dagger.Binds import dagger.Module @@ -36,15 +36,15 @@ interface CustomTileModule { @Binds fun bindDataInteractor( dataInteractor: CustomTileInteractor - ): QSTileDataInteractor<CustomTileData> + ): QSTileDataInteractor<CustomTileDataModel> @Binds fun bindUserActionInteractor( userActionInteractor: CustomTileUserActionInteractor - ): QSTileUserActionInteractor<CustomTileData> + ): QSTileUserActionInteractor<CustomTileDataModel> @Binds - fun bindMapper(customTileMapper: CustomTileMapper): QSTileDataToStateMapper<CustomTileData> + fun bindMapper(customTileMapper: CustomTileMapper): QSTileDataToStateMapper<CustomTileDataModel> @Binds fun bindCustomTileDefaultsRepository( diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/CustomTileData.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/domain/entity/CustomTileDataModel.kt index bb5a229a0696..f095c01126c4 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/CustomTileData.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/domain/entity/CustomTileDataModel.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.qs.tiles.impl.custom +package com.android.systemui.qs.tiles.impl.custom.domain.entity import android.content.ComponentName import android.graphics.drawable.Icon @@ -22,12 +22,11 @@ import android.os.UserHandle import android.service.quicksettings.Tile import com.android.systemui.qs.tiles.impl.custom.di.bound.CustomTileBoundComponent -data class CustomTileData( +data class CustomTileDataModel( val user: UserHandle, val componentName: ComponentName, val tile: Tile, val callingAppUid: Int, - val isActive: Boolean, val hasPendingBind: Boolean, val shouldShowChevron: Boolean, val defaultTileLabel: CharSequence?, diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileConfigProvider.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileConfigProvider.kt index 3f3b94e65294..0609e797d53b 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileConfigProvider.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileConfigProvider.kt @@ -18,20 +18,31 @@ package com.android.systemui.qs.tiles.viewmodel import com.android.internal.util.Preconditions import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.qs.QsEventLogger +import com.android.systemui.qs.pipeline.shared.TileSpec import javax.inject.Inject interface QSTileConfigProvider { /** - * Returns a [QSTileConfig] for a [tileSpec] or throws [IllegalArgumentException] if there is no - * config for such [tileSpec]. + * Returns a [QSTileConfig] for a [tileSpec]: + * - injected config for [TileSpec.PlatformTileSpec] or throws [IllegalArgumentException] if + * there is none + * - new config for [TileSpec.CustomTileSpec]. + * - throws [IllegalArgumentException] for [TileSpec.Invalid] */ fun getConfig(tileSpec: String): QSTileConfig + + fun hasConfig(tileSpec: String): Boolean } @SysUISingleton -class QSTileConfigProviderImpl @Inject constructor(private val configs: Map<String, QSTileConfig>) : - QSTileConfigProvider { +class QSTileConfigProviderImpl +@Inject +constructor( + private val configs: Map<String, QSTileConfig>, + private val qsEventLogger: QsEventLogger, +) : QSTileConfigProvider { init { for (entry in configs.entries) { @@ -44,6 +55,26 @@ class QSTileConfigProviderImpl @Inject constructor(private val configs: Map<Stri } } + override fun hasConfig(tileSpec: String): Boolean = + when (TileSpec.create(tileSpec)) { + is TileSpec.PlatformTileSpec -> configs.containsKey(tileSpec) + is TileSpec.CustomTileSpec -> true + is TileSpec.Invalid -> false + } + override fun getConfig(tileSpec: String): QSTileConfig = - configs[tileSpec] ?: throw IllegalArgumentException("There is no config for spec=$tileSpec") + when (val spec = TileSpec.create(tileSpec)) { + is TileSpec.PlatformTileSpec -> { + configs[tileSpec] + ?: throw IllegalArgumentException("There is no config for spec=$tileSpec") + } + is TileSpec.CustomTileSpec -> + QSTileConfig( + spec, + QSTileUIConfig.Empty, + qsEventLogger.getNewInstanceId(), + ) + is TileSpec.Invalid -> + throw IllegalArgumentException("TileSpec.Invalid doesn't support configs") + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/viewmodel/QSTileConfigProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/viewmodel/QSTileConfigProviderTest.kt index 682b2d0d3983..5eca8caa7d15 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/viewmodel/QSTileConfigProviderTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/viewmodel/QSTileConfigProviderTest.kt @@ -19,7 +19,9 @@ package com.android.systemui.qs.tiles.viewmodel import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase +import com.android.systemui.qs.QsEventLogger import com.android.systemui.qs.pipeline.shared.TileSpec +import com.android.systemui.util.mockito.mock import com.google.common.truth.Truth.assertThat import org.junit.Test import org.junit.runner.RunWith @@ -29,8 +31,8 @@ import org.junit.runner.RunWith class QSTileConfigProviderTest : SysuiTestCase() { private val underTest = - QSTileConfigProviderImpl( - mapOf(VALID_SPEC.spec to QSTileConfigTestBuilder.build { tileSpec = VALID_SPEC }) + createQSTileConfigProviderImpl( + mapOf(VALID_SPEC.spec to QSTileConfigTestBuilder.build { tileSpec = VALID_SPEC }), ) @Test @@ -43,13 +45,31 @@ class QSTileConfigProviderTest : SysuiTestCase() { underTest.getConfig(INVALID_SPEC.spec) } + @Test + fun hasConfigReturnsTrueForValidSpec() { + assertThat(underTest.hasConfig(VALID_SPEC.spec)).isTrue() + } + + @Test + fun hasConfigReturnsFalseForInvalidSpec() { + assertThat(underTest.hasConfig(INVALID_SPEC.spec)).isFalse() + } + @Test(expected = IllegalArgumentException::class) fun validatesSpecUponCreation() { - QSTileConfigProviderImpl( + createQSTileConfigProviderImpl( mapOf(VALID_SPEC.spec to QSTileConfigTestBuilder.build { tileSpec = INVALID_SPEC }) ) } + private fun createQSTileConfigProviderImpl( + configs: Map<String, QSTileConfig> + ): QSTileConfigProviderImpl = + QSTileConfigProviderImpl( + configs, + mock<QsEventLogger>(), + ) + private companion object { val VALID_SPEC = TileSpec.create("valid_tile_spec") diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/viewmodel/FakeQSTileConfigProvider.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/viewmodel/FakeQSTileConfigProvider.kt index de72a7dc30d7..d231d63a3906 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/viewmodel/FakeQSTileConfigProvider.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/viewmodel/FakeQSTileConfigProvider.kt @@ -24,6 +24,8 @@ class FakeQSTileConfigProvider : QSTileConfigProvider { override fun getConfig(tileSpec: String): QSTileConfig = configs.getValue(tileSpec) + override fun hasConfig(tileSpec: String): Boolean = configs.containsKey(tileSpec) + fun putConfig(tileSpec: TileSpec, config: QSTileConfig) { configs[tileSpec.spec] = config } |