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 package com.android.systemui.unfold.data.repository
17 
18 import androidx.annotation.FloatRange
19 import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
20 import com.android.systemui.unfold.UnfoldTransitionProgressProvider
21 import com.android.systemui.unfold.data.repository.UnfoldTransitionStatus.TransitionFinished
22 import com.android.systemui.unfold.data.repository.UnfoldTransitionStatus.TransitionInProgress
23 import com.android.systemui.unfold.data.repository.UnfoldTransitionStatus.TransitionStarted
24 import com.android.systemui.util.kotlin.getOrNull
25 import java.util.Optional
26 import javax.inject.Inject
27 import kotlinx.coroutines.channels.awaitClose
28 import kotlinx.coroutines.flow.Flow
29 import kotlinx.coroutines.flow.emptyFlow
30 
31 /** Repository for fold/unfold transitions */
32 interface UnfoldTransitionRepository {
33     /** Returns false if fold/unfold transitions are not available on this device */
34     val isAvailable: Boolean
35 
36     /**
37      * Emits current transition state on each transition change such as transition start or finish
38      * [UnfoldTransitionStatus]
39      */
40     val transitionStatus: Flow<UnfoldTransitionStatus>
41 }
42 
43 /** Transition event of fold/unfold transition */
44 sealed class UnfoldTransitionStatus {
45     /** Status that is sent when fold or unfold transition is in started state */
46     data object TransitionStarted : UnfoldTransitionStatus()
47     /** Status that is sent while fold or unfold transition is in progress */
48     data class TransitionInProgress(
49         @FloatRange(from = 0.0, to = 1.0) val progress: Float,
50     ) : UnfoldTransitionStatus()
51     /** Status that is sent when fold or unfold transition is finished */
52     data object TransitionFinished : UnfoldTransitionStatus()
53 }
54 
55 class UnfoldTransitionRepositoryImpl
56 @Inject
57 constructor(
58     private val unfoldProgressProvider: Optional<UnfoldTransitionProgressProvider>,
59 ) : UnfoldTransitionRepository {
60 
61     override val isAvailable: Boolean
62         get() = unfoldProgressProvider.isPresent
63 
64     override val transitionStatus: Flow<UnfoldTransitionStatus>
65         get() {
66             val provider = unfoldProgressProvider.getOrNull() ?: return emptyFlow()
67 
<lambda>null68             return conflatedCallbackFlow {
69                 val callback =
70                     object : UnfoldTransitionProgressProvider.TransitionProgressListener {
71                         override fun onTransitionStarted() {
72                             trySend(TransitionStarted)
73                         }
74 
75                         override fun onTransitionProgress(progress: Float) {
76                             trySend(TransitionInProgress(progress))
77                         }
78 
79                         override fun onTransitionFinished() {
80                             trySend(TransitionFinished)
81                         }
82                     }
83                 provider.addCallback(callback)
84                 awaitClose { provider.removeCallback(callback) }
85             }
86         }
87 }
88