1 /* 2 * Copyright (C) 2023 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 */ 17 18 package com.android.systemui.keyguard.data.repository 19 20 import androidx.constraintlayout.widget.ConstraintSet 21 import com.android.systemui.common.ui.data.repository.ConfigurationRepository 22 import com.android.systemui.dagger.SysUISingleton 23 import com.android.systemui.dagger.qualifiers.Application 24 import com.android.systemui.keyguard.ui.view.layout.blueprints.DefaultKeyguardBlueprint.Companion.DEFAULT 25 import com.android.systemui.keyguard.ui.view.layout.blueprints.KeyguardBlueprintModule 26 import java.io.PrintWriter 27 import javax.inject.Inject 28 import kotlinx.coroutines.CoroutineScope 29 import kotlinx.coroutines.flow.Flow 30 import kotlinx.coroutines.flow.MutableSharedFlow 31 import kotlinx.coroutines.flow.asSharedFlow 32 import kotlinx.coroutines.launch 33 34 /** 35 * Manages blueprint changes for the lockscreen. 36 * 37 * To add a blueprint, create a class that implements LockscreenBlueprint and bind it to the map in 38 * the dagger module: 39 * 40 * A Blueprint determines how the layout should be constrained on a high level. 41 * 42 * A Section is a modular piece of code that implements the constraints. The blueprint uses the 43 * sections to define the constraints. 44 * 45 * @see KeyguardBlueprintModule 46 */ 47 @SysUISingleton 48 class KeyguardBlueprintRepository 49 @Inject 50 constructor( 51 configurationRepository: ConfigurationRepository, 52 blueprints: Set<@JvmSuppressWildcards KeyguardBlueprint>, 53 @Application private val applicationScope: CoroutineScope, 54 ) { 55 private val blueprintIdMap: Map<String, KeyguardBlueprint> = blueprints.associateBy { it.id } 56 private val _blueprint: MutableSharedFlow<KeyguardBlueprint> = MutableSharedFlow(replay = 1) 57 val blueprint: Flow<KeyguardBlueprint> = _blueprint.asSharedFlow() 58 59 init { 60 applyBlueprint(blueprintIdMap[DEFAULT]!!) 61 applicationScope.launch { 62 configurationRepository.onAnyConfigurationChange.collect { refreshBlueprint() } 63 } 64 } 65 66 /** 67 * Emits the blueprint value to the collectors. 68 * 69 * @param blueprintId 70 * @return whether the transition has succeeded. 71 */ 72 fun applyBlueprint(blueprintId: String?): Boolean { 73 val blueprint = blueprintIdMap[blueprintId] ?: return false 74 applyBlueprint(blueprint) 75 return true 76 } 77 78 /** Emits the blueprint value to the collectors. */ 79 fun applyBlueprint(blueprint: KeyguardBlueprint?) { 80 blueprint?.let { _blueprint.tryEmit(it) } 81 } 82 83 /** Re-emits the last emitted blueprint value if possible. */ 84 fun refreshBlueprint() { 85 if (_blueprint.replayCache.isNotEmpty()) { 86 _blueprint.tryEmit(_blueprint.replayCache.last()) 87 } 88 } 89 90 /** Prints all available blueprints to the PrintWriter. */ 91 fun printBlueprints(pw: PrintWriter) { 92 blueprintIdMap.forEach { entry -> pw.println("${entry.key}") } 93 } 94 } 95 96 /** Determines the constraints for the ConstraintSet in the lockscreen root view. */ 97 interface KeyguardBlueprint { 98 val id: String 99 100 fun apply(constraintSet: ConstraintSet) 101 } 102 103 /** 104 * Lower level modules that determine constraints for a particular section in the lockscreen root 105 * view. 106 */ 107 interface KeyguardSection { 108 fun apply(constraintSet: ConstraintSet) 109 } 110