[flexiglass] Simplified Dagger setup.

Simplifies the story for how we provide Flexiglass objects through
Dagger and prepares it all for nicer/simpler injection into the
soon-to-be Flexiglass container view.

Bug: 279501596
Test: Built and ran the Compose gallery app with useCompose = false
Test: Built and ran System UI with useCompose = true and useCompose =
false

Change-Id: Ic820caa3067a0fd3a281a4ca68a2af1356276d7b
This commit is contained in:
Alejandro Nijamkin
2023-05-18 15:40:24 -07:00
parent 72ace2744f
commit da01ed6a1d
12 changed files with 240 additions and 92 deletions

View File

@@ -17,10 +17,12 @@
package com.android.systemui.scene.ui.composable
import com.android.systemui.scene.shared.model.Scene
import com.android.systemui.scene.shared.model.SceneContainerNames
import dagger.Module
import dagger.multibindings.Multibinds
import javax.inject.Named
@Module
interface SceneModule {
@Multibinds fun scenes(): Set<Scene>
@Multibinds @Named(SceneContainerNames.SYSTEM_UI_DEFAULT) fun scenes(): Set<Scene>
}

View File

@@ -17,22 +17,32 @@
package com.android.systemui.scene.ui.composable
import com.android.systemui.bouncer.ui.composable.BouncerScene
import com.android.systemui.bouncer.ui.viewmodel.BouncerViewModel
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.ui.composable.LockscreenScene
import com.android.systemui.keyguard.ui.viewmodel.LockscreenSceneViewModel
import com.android.systemui.qs.ui.composable.QuickSettingsScene
import com.android.systemui.qs.ui.viewmodel.QuickSettingsSceneViewModel
import com.android.systemui.scene.shared.model.Scene
import com.android.systemui.scene.shared.model.SceneContainerNames
import com.android.systemui.shade.ui.composable.ShadeScene
import com.android.systemui.shade.ui.viewmodel.ShadeSceneViewModel
import dagger.Module
import dagger.Provides
import javax.inject.Named
import kotlinx.coroutines.CoroutineScope
@Module
object SceneModule {
@Provides
@Named(SceneContainerNames.SYSTEM_UI_DEFAULT)
fun scenes(
bouncer: BouncerScene,
gone: GoneScene,
lockScreen: LockscreenScene,
qs: QuickSettingsScene,
shade: ShadeScene,
@Named(SceneContainerNames.SYSTEM_UI_DEFAULT) bouncer: BouncerScene,
@Named(SceneContainerNames.SYSTEM_UI_DEFAULT) gone: GoneScene,
@Named(SceneContainerNames.SYSTEM_UI_DEFAULT) lockScreen: LockscreenScene,
@Named(SceneContainerNames.SYSTEM_UI_DEFAULT) qs: QuickSettingsScene,
@Named(SceneContainerNames.SYSTEM_UI_DEFAULT) shade: ShadeScene,
): Set<Scene> {
return setOf(
bouncer,
@@ -42,4 +52,71 @@ object SceneModule {
shade,
)
}
@Provides
@SysUISingleton
@Named(SceneContainerNames.SYSTEM_UI_DEFAULT)
fun bouncerScene(
viewModelFactory: BouncerViewModel.Factory,
): BouncerScene {
return BouncerScene(
viewModel =
viewModelFactory.create(
containerName = SceneContainerNames.SYSTEM_UI_DEFAULT,
),
)
}
@Provides
@SysUISingleton
@Named(SceneContainerNames.SYSTEM_UI_DEFAULT)
fun goneScene(): GoneScene {
return GoneScene()
}
@Provides
@SysUISingleton
@Named(SceneContainerNames.SYSTEM_UI_DEFAULT)
fun lockscreenScene(
@Application applicationScope: CoroutineScope,
viewModelFactory: LockscreenSceneViewModel.Factory,
): LockscreenScene {
return LockscreenScene(
applicationScope = applicationScope,
viewModel =
viewModelFactory.create(
containerName = SceneContainerNames.SYSTEM_UI_DEFAULT,
),
)
}
@Provides
@SysUISingleton
@Named(SceneContainerNames.SYSTEM_UI_DEFAULT)
fun quickSettingsScene(
viewModelFactory: QuickSettingsSceneViewModel.Factory,
): QuickSettingsScene {
return QuickSettingsScene(
viewModel =
viewModelFactory.create(
containerName = SceneContainerNames.SYSTEM_UI_DEFAULT,
),
)
}
@Provides
@SysUISingleton
@Named(SceneContainerNames.SYSTEM_UI_DEFAULT)
fun shadeScene(
@Application applicationScope: CoroutineScope,
viewModelFactory: ShadeSceneViewModel.Factory,
): ShadeScene {
return ShadeScene(
applicationScope = applicationScope,
viewModel =
viewModelFactory.create(
containerName = SceneContainerNames.SYSTEM_UI_DEFAULT,
),
)
}
}

View File

@@ -40,22 +40,17 @@ import com.android.systemui.bouncer.ui.viewmodel.BouncerViewModel
import com.android.systemui.bouncer.ui.viewmodel.PasswordBouncerViewModel
import com.android.systemui.bouncer.ui.viewmodel.PatternBouncerViewModel
import com.android.systemui.bouncer.ui.viewmodel.PinBouncerViewModel
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneModel
import com.android.systemui.scene.shared.model.UserAction
import com.android.systemui.scene.ui.composable.ComposableScene
import javax.inject.Inject
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
/** The bouncer scene displays authentication challenges like PIN, password, or pattern. */
@SysUISingleton
class BouncerScene
@Inject
constructor(
private val viewModelFactory: BouncerViewModel.Factory,
class BouncerScene(
private val viewModel: BouncerViewModel,
) : ComposableScene {
override val key = SceneKey.Bouncer
@@ -73,7 +68,7 @@ constructor(
override fun Content(
containerName: String,
modifier: Modifier,
) = BouncerScene(viewModelFactory.create(containerName), modifier)
) = BouncerScene(viewModel, modifier)
}
@Composable

View File

@@ -31,7 +31,6 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.common.ui.compose.Icon
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.ui.viewmodel.LockscreenSceneViewModel
import com.android.systemui.scene.shared.model.Direction
@@ -39,7 +38,6 @@ import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneModel
import com.android.systemui.scene.shared.model.UserAction
import com.android.systemui.scene.ui.composable.ComposableScene
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
@@ -47,29 +45,22 @@ import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
/** The lock screen scene shows when the device is locked. */
@SysUISingleton
class LockscreenScene
@Inject
constructor(
class LockscreenScene(
@Application private val applicationScope: CoroutineScope,
private val viewModelFactory: LockscreenSceneViewModel.Factory,
private val viewModel: LockscreenSceneViewModel,
) : ComposableScene {
override val key = SceneKey.Lockscreen
private var unsafeViewModel: LockscreenSceneViewModel? = null
override fun destinationScenes(
containerName: String,
): StateFlow<Map<UserAction, SceneModel>> =
getOrCreateViewModelSingleton(containerName).let { viewModel ->
viewModel.upDestinationSceneKey
.map { pageKey -> destinationScenes(up = pageKey) }
.stateIn(
scope = applicationScope,
started = SharingStarted.Eagerly,
initialValue = destinationScenes(up = viewModel.upDestinationSceneKey.value)
)
}
viewModel.upDestinationSceneKey
.map { pageKey -> destinationScenes(up = pageKey) }
.stateIn(
scope = applicationScope,
started = SharingStarted.Eagerly,
initialValue = destinationScenes(up = viewModel.upDestinationSceneKey.value)
)
@Composable
override fun Content(
@@ -77,7 +68,7 @@ constructor(
modifier: Modifier,
) {
LockscreenScene(
viewModel = getOrCreateViewModelSingleton(containerName),
viewModel = viewModel,
modifier = modifier,
)
}
@@ -90,13 +81,6 @@ constructor(
UserAction.Swipe(Direction.DOWN) to SceneModel(SceneKey.Shade)
)
}
private fun getOrCreateViewModelSingleton(
containerName: String,
): LockscreenSceneViewModel {
return unsafeViewModel
?: viewModelFactory.create(containerName).also { unsafeViewModel = it }
}
}
@Composable

View File

@@ -27,24 +27,19 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.qs.ui.viewmodel.QuickSettingsSceneViewModel
import com.android.systemui.scene.shared.model.Direction
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneModel
import com.android.systemui.scene.shared.model.UserAction
import com.android.systemui.scene.ui.composable.ComposableScene
import javax.inject.Inject
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
/** The Quick Settings (AKA "QS") scene shows the quick setting tiles. */
@SysUISingleton
class QuickSettingsScene
@Inject
constructor(
private val viewModelFactory: QuickSettingsSceneViewModel.Factory,
class QuickSettingsScene(
private val viewModel: QuickSettingsSceneViewModel,
) : ComposableScene {
override val key = SceneKey.QuickSettings
@@ -64,7 +59,7 @@ constructor(
modifier: Modifier,
) {
QuickSettingsScene(
viewModel = viewModelFactory.create(containerName),
viewModel = viewModel,
modifier = modifier,
)
}

View File

@@ -23,12 +23,10 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.scene.shared.model.Direction
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneModel
import com.android.systemui.scene.shared.model.UserAction
import javax.inject.Inject
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
@@ -37,8 +35,7 @@ import kotlinx.coroutines.flow.asStateFlow
* "Gone" is not a real scene but rather the absence of scenes when we want to skip showing any
* content from the scene framework.
*/
@SysUISingleton
class GoneScene @Inject constructor() : ComposableScene {
class GoneScene : ComposableScene {
override val key = SceneKey.Gone
override fun destinationScenes(

View File

@@ -27,7 +27,6 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.scene.shared.model.Direction
import com.android.systemui.scene.shared.model.SceneKey
@@ -35,7 +34,6 @@ import com.android.systemui.scene.shared.model.SceneModel
import com.android.systemui.scene.shared.model.UserAction
import com.android.systemui.scene.ui.composable.ComposableScene
import com.android.systemui.shade.ui.viewmodel.ShadeSceneViewModel
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
@@ -43,29 +41,22 @@ import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
/** The shade scene shows scrolling list of notifications and some of the quick setting tiles. */
@SysUISingleton
class ShadeScene
@Inject
constructor(
class ShadeScene(
@Application private val applicationScope: CoroutineScope,
private val viewModelFactory: ShadeSceneViewModel.Factory,
private val viewModel: ShadeSceneViewModel,
) : ComposableScene {
override val key = SceneKey.Shade
private var unsafeViewModel: ShadeSceneViewModel? = null
override fun destinationScenes(
containerName: String,
): StateFlow<Map<UserAction, SceneModel>> =
getOrCreateViewModelSingleton(containerName).let { viewModel ->
viewModel.upDestinationSceneKey
.map { sceneKey -> destinationScenes(up = sceneKey) }
.stateIn(
scope = applicationScope,
started = SharingStarted.Eagerly,
initialValue = destinationScenes(up = viewModel.upDestinationSceneKey.value),
)
}
viewModel.upDestinationSceneKey
.map { sceneKey -> destinationScenes(up = sceneKey) }
.stateIn(
scope = applicationScope,
started = SharingStarted.Eagerly,
initialValue = destinationScenes(up = viewModel.upDestinationSceneKey.value),
)
@Composable
override fun Content(
@@ -73,7 +64,7 @@ constructor(
modifier: Modifier,
) {
ShadeScene(
viewModel = getOrCreateViewModelSingleton(containerName),
viewModel = viewModel,
modifier = modifier,
)
}
@@ -86,13 +77,6 @@ constructor(
UserAction.Swipe(Direction.DOWN) to SceneModel(SceneKey.QuickSettings),
)
}
private fun getOrCreateViewModelSingleton(
containerName: String,
): ShadeSceneViewModel {
return unsafeViewModel
?: viewModelFactory.create(containerName).also { unsafeViewModel = it }
}
}
@Composable

View File

@@ -16,12 +16,16 @@
package com.android.systemui.scene
import com.android.systemui.scene.data.model.SceneContainerConfigModule
import com.android.systemui.scene.ui.composable.SceneModule
import com.android.systemui.scene.ui.viewmodel.SceneContainerViewModelModule
import dagger.Module
@Module(
includes =
[
SceneContainerConfigModule::class,
SceneContainerViewModelModule::class,
SceneModule::class,
],
)

View File

@@ -0,0 +1,61 @@
/*
* Copyright (C) 2023 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.scene.data.model
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.scene.shared.model.SceneContainerNames
import com.android.systemui.scene.shared.model.SceneKey
import dagger.Module
import dagger.Provides
import javax.inject.Named
@Module
object SceneContainerConfigModule {
@Provides
fun containerConfigs(): Map<String, SceneContainerConfig> {
return mapOf(
SceneContainerNames.SYSTEM_UI_DEFAULT to
SceneContainerConfig(
name = SceneContainerNames.SYSTEM_UI_DEFAULT,
// Note that this list is in z-order. The first one is the bottom-most and the
// last
// one is top-most.
sceneKeys =
listOf(
SceneKey.Gone,
SceneKey.Lockscreen,
SceneKey.Bouncer,
SceneKey.Shade,
SceneKey.QuickSettings,
),
initialSceneKey = SceneKey.Lockscreen,
),
)
}
@Provides
@SysUISingleton
@Named(SceneContainerNames.SYSTEM_UI_DEFAULT)
fun provideDefaultSceneContainerConfig(
configs: Map<String, SceneContainerConfig>,
): SceneContainerConfig {
return checkNotNull(configs[SceneContainerNames.SYSTEM_UI_DEFAULT]) {
"No SceneContainerConfig named \"${SceneContainerNames.SYSTEM_UI_DEFAULT}\"."
}
}
}

View File

@@ -0,0 +1,21 @@
/*
* Copyright (C) 2023 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.scene.shared.model
object SceneContainerNames {
const val SYSTEM_UI_DEFAULT = "system_ui"
}

View File

@@ -19,17 +19,12 @@ package com.android.systemui.scene.ui.viewmodel
import com.android.systemui.scene.domain.interactor.SceneInteractor
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneModel
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import kotlinx.coroutines.flow.StateFlow
/** Models UI state for a single scene container. */
class SceneContainerViewModel
@AssistedInject
constructor(
class SceneContainerViewModel(
private val interactor: SceneInteractor,
@Assisted val containerName: String,
val containerName: String,
) {
/**
* Keys of all scenes in the container.
@@ -54,11 +49,4 @@ constructor(
fun setSceneTransitionProgress(progress: Float) {
interactor.setSceneTransitionProgress(containerName, progress)
}
@AssistedFactory
interface Factory {
fun create(
containerName: String,
): SceneContainerViewModel
}
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright (C) 2023 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.scene.ui.viewmodel
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.scene.domain.interactor.SceneInteractor
import com.android.systemui.scene.shared.model.SceneContainerNames
import dagger.Module
import dagger.Provides
import javax.inject.Named
@Module
object SceneContainerViewModelModule {
@Provides
@SysUISingleton
@Named(SceneContainerNames.SYSTEM_UI_DEFAULT)
fun defaultSceneContainerViewModel(
interactor: SceneInteractor,
): SceneContainerViewModel {
return SceneContainerViewModel(
interactor = interactor,
containerName = SceneContainerNames.SYSTEM_UI_DEFAULT,
)
}
}