• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.ui.viewmodel
19 
20 import android.os.Handler
21 import android.transition.Transition
22 import android.transition.TransitionManager
23 import androidx.constraintlayout.widget.ConstraintLayout
24 import com.android.systemui.dagger.qualifiers.Main
25 import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor
26 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
27 import com.android.systemui.keyguard.shared.model.KeyguardState
28 import com.android.systemui.keyguard.ui.view.layout.blueprints.transitions.IntraBlueprintTransition
29 import com.android.systemui.keyguard.ui.view.layout.blueprints.transitions.IntraBlueprintTransition.Config
30 import com.android.systemui.keyguard.ui.view.layout.blueprints.transitions.IntraBlueprintTransition.Type
31 import com.android.systemui.log.LogBuffer
32 import com.android.systemui.log.core.Logger
33 import com.android.systemui.log.dagger.KeyguardBlueprintLog
34 import javax.inject.Inject
35 import kotlinx.coroutines.flow.MutableStateFlow
36 import kotlinx.coroutines.flow.asStateFlow
37 
38 data class TransitionData(val config: Config, val start: Long = System.currentTimeMillis())
39 
40 class KeyguardBlueprintViewModel
41 @Inject
42 constructor(
43     @Main private val handler: Handler,
44     private val keyguardBlueprintInteractor: KeyguardBlueprintInteractor,
45     private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
46     @KeyguardBlueprintLog private val blueprintLog: LogBuffer,
47 ) {
48     private val logger = Logger(blueprintLog, "KeyguardBlueprintViewModel")
49     val blueprint = keyguardBlueprintInteractor.blueprint
50     val blueprintId = keyguardBlueprintInteractor.blueprintId
51     val refreshTransition = keyguardBlueprintInteractor.refreshTransition
52 
53     private val _currentTransition = MutableStateFlow<TransitionData?>(null)
54     val currentTransition = _currentTransition.asStateFlow()
55 
56     private val runningTransitions = mutableSetOf<Transition>()
57     private val transitionListener =
58         object : Transition.TransitionListener {
onTransitionCancelnull59             override fun onTransitionCancel(transition: Transition) {
60                 logger.w({ "onTransitionCancel: $str1" }) { str1 = transition::class.simpleName }
61                 updateTransitions(null) { remove(transition) }
62             }
63 
onTransitionEndnull64             override fun onTransitionEnd(transition: Transition) {
65                 logger.i({ "onTransitionEnd: $str1" }) { str1 = transition::class.simpleName }
66                 updateTransitions(null) { remove(transition) }
67             }
68 
onTransitionPausenull69             override fun onTransitionPause(transition: Transition) {
70                 logger.i({ "onTransitionPause: $str1" }) { str1 = transition::class.simpleName }
71                 updateTransitions(null) { remove(transition) }
72             }
73 
onTransitionResumenull74             override fun onTransitionResume(transition: Transition) {
75                 logger.i({ "onTransitionResume: $str1" }) { str1 = transition::class.simpleName }
76                 updateTransitions(null) { add(transition) }
77             }
78 
onTransitionStartnull79             override fun onTransitionStart(transition: Transition) {
80                 logger.i({ "onTransitionStart: $str1" }) { str1 = transition::class.simpleName }
81                 updateTransitions(null) { add(transition) }
82             }
83         }
84 
refreshBlueprintnull85     fun refreshBlueprint(type: Type = Type.NoTransition) =
86         keyguardBlueprintInteractor.refreshBlueprint(type)
87 
88     fun updateTransitions(data: TransitionData?, mutate: MutableSet<Transition>.() -> Unit) {
89         runningTransitions.mutate()
90 
91         if (runningTransitions.size <= 0) _currentTransition.value = null
92         else if (data != null) _currentTransition.value = data
93     }
94 
runTransitionnull95     fun runTransition(
96         constraintLayout: ConstraintLayout,
97         clockViewModel: KeyguardClockViewModel,
98         smartspaceViewModel: KeyguardSmartspaceViewModel,
99         config: Config,
100         apply: () -> Unit,
101     ) {
102         val newConfig =
103             if (keyguardTransitionInteractor.getCurrentState() == KeyguardState.OFF) {
104                 config.copy(type = Type.Init)
105             } else {
106                 config
107             }
108 
109         runTransition(
110             constraintLayout,
111             IntraBlueprintTransition(newConfig, clockViewModel, smartspaceViewModel, blueprintLog),
112             config,
113             apply,
114         )
115     }
116 
runTransitionnull117     fun runTransition(
118         constraintLayout: ConstraintLayout,
119         transition: Transition,
120         config: Config,
121         apply: () -> Unit,
122     ) {
123         val currentPriority = currentTransition.value?.let { it.config.type.priority } ?: -1
124         if (config.checkPriority && config.type.priority < currentPriority) {
125             logger.w({ "runTransition: skipping $str1: currentPriority=$int1; config=$str2" }) {
126                 str1 = transition::class.simpleName
127                 int1 = currentPriority
128                 str2 = "$config"
129             }
130             apply()
131             return
132         }
133 
134         // Don't allow transitions with animations while in OFF state
135         val newConfig =
136             if (keyguardTransitionInteractor.getCurrentState() == KeyguardState.OFF) {
137                 config.copy(type = Type.Init)
138             } else {
139                 config
140             }
141 
142         logger.i({ "runTransition: running $str1: currentPriority=$int1; config=$str2" }) {
143             str1 = transition::class.simpleName
144             int1 = currentPriority
145             str2 = "$newConfig"
146         }
147 
148         // beginDelayedTransition makes a copy, so we temporarially add the uncopied transition to
149         // the running set until the copy is started by the handler.
150         updateTransitions(TransitionData(newConfig)) { add(transition) }
151         transition.addListener(transitionListener)
152 
153         handler.post {
154             if (newConfig.terminatePrevious) {
155                 TransitionManager.endTransitions(constraintLayout)
156             }
157 
158             TransitionManager.beginDelayedTransition(constraintLayout, transition)
159             apply()
160 
161             // Delay removal until after copied transition has started
162             handler.post { updateTransitions(null) { remove(transition) } }
163         }
164     }
165 }
166